9c8a575a-6c74-4b77-8ed9-1836a7f81e09
This commit is contained in:
4
auth-state.json
Normal file
4
auth-state.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"cookies": [],
|
||||
"origins": []
|
||||
}
|
||||
BIN
db/custom.db
BIN
db/custom.db
Binary file not shown.
@@ -179,6 +179,7 @@ model ChatSession {
|
||||
telegramId String? @map("telegram_id")
|
||||
leadId Int? @map("lead_id")
|
||||
messages String // JSON array of {role, content, timestamp}
|
||||
language String @default("en")
|
||||
device String?
|
||||
ip String?
|
||||
country String?
|
||||
|
||||
@@ -17,6 +17,7 @@ const CHATBOT_KEYS = [
|
||||
'chatbot_provider',
|
||||
'chatbot_api_endpoint',
|
||||
'chatbot_api_key',
|
||||
'chatbot_model',
|
||||
] as const;
|
||||
|
||||
const DEFAULTS: Record<string, string> = {
|
||||
@@ -30,9 +31,10 @@ const DEFAULTS: Record<string, string> = {
|
||||
chatbot_max_tokens: '1024',
|
||||
chatbot_max_history: '20',
|
||||
chatbot_knowledge_base: '',
|
||||
chatbot_provider: 'openai',
|
||||
chatbot_api_endpoint: '',
|
||||
chatbot_provider: 'ollama',
|
||||
chatbot_api_endpoint: 'https://ollama.com/v1/chat/completions',
|
||||
chatbot_api_key: '',
|
||||
chatbot_model: 'deepseek-v4-flash:preview',
|
||||
};
|
||||
|
||||
function maskApiKey(value: string): string {
|
||||
|
||||
@@ -5,14 +5,31 @@ import { getChatbotConfig } from '@/lib/chatbot-config';
|
||||
const DEFAULTS: Record<string, string> = {
|
||||
chatbot_enabled: 'false',
|
||||
chatbot_sleep_mode: 'false',
|
||||
chatbot_sleep_message: 'Извините, мы сейчас не доступны. Напишите позже, пожалуйста.',
|
||||
chatbot_sleep_message:
|
||||
'Извините, мы сейчас не доступны. Напишите позже, пожалуйста.',
|
||||
chatbot_system_prompt:
|
||||
'Ты — дружелюбный ассистент интернет-магазина. Отвечай на вопросы клиентов о товарах, ценах, доставке. Будь вежливым и полезным.',
|
||||
chatbot_temperature: '0.7',
|
||||
chatbot_max_tokens: '1024',
|
||||
chatbot_max_history: '20',
|
||||
chatbot_knowledge_base: '',
|
||||
chatbot_provider: 'ollama',
|
||||
chatbot_api_endpoint: 'https://ollama.com/v1/chat/completions',
|
||||
chatbot_api_key: '',
|
||||
chatbot_model: 'deepseek-v4-flash:preview',
|
||||
};
|
||||
|
||||
const LANGUAGE_INSTRUCTIONS: Record<string, string> = {
|
||||
ru: 'ВАЖНО: Отвечай ТОЛЬКО на русском языке. Все ответы должны быть на русском.',
|
||||
en: 'IMPORTANT: Respond ONLY in English. All responses must be in English.',
|
||||
es: 'IMPORTANTE: Responde SOLO en español. Todas las respuestas deben estar en español.',
|
||||
ar: 'مهم: أجب فقط باللغة العربية. جميع الردود يجب أن تكون بالعربية.',
|
||||
fr: 'IMPORTANT: Répondez UNIQUEMENT en français.',
|
||||
de: 'WICHTIG: Antworte AUSSCHLIESSLICH auf Deutsch.',
|
||||
zh: '重要:只用中文回答。所有回复必须使用中文。',
|
||||
pt: 'IMPORTANTE: Responda APENAS em português.',
|
||||
tr: 'ÖNEMLİ: Sadece Türkçe cevap ver.',
|
||||
hi: 'महत्वपूर्ण: कृपया केवल हिंदी में उत्तर दें।',
|
||||
};
|
||||
|
||||
interface ChatMessage {
|
||||
@@ -25,7 +42,6 @@ function getConfig(config: Record<string, string>, key: string, fallback: string
|
||||
return config[key] || fallback;
|
||||
}
|
||||
|
||||
// Extract lead data from message history using regex
|
||||
function extractLeadData(messages: ChatMessage[]): {
|
||||
name?: string;
|
||||
phone?: string;
|
||||
@@ -35,7 +51,6 @@ function extractLeadData(messages: ChatMessage[]): {
|
||||
const result: { name?: string; phone?: string; email?: string; telegram?: string } = {};
|
||||
const allText = messages.map((m) => m.content).join(' ');
|
||||
|
||||
// Phone: various formats
|
||||
const phoneMatch = allText.match(
|
||||
/(?:\+?\d[\s\-\(]?){7,}\d|\+?\d{1,3}[\s\-]?\(?\d{2,4}\)?[\s\-]?\d{2,4}[\s\-]?\d{2,4}/,
|
||||
);
|
||||
@@ -43,19 +58,16 @@ function extractLeadData(messages: ChatMessage[]): {
|
||||
result.phone = phoneMatch[0].replace(/\s+/g, ' ').trim();
|
||||
}
|
||||
|
||||
// Email
|
||||
const emailMatch = allText.match(/[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}/);
|
||||
if (emailMatch) {
|
||||
result.email = emailMatch[0];
|
||||
}
|
||||
|
||||
// Telegram handle
|
||||
const tgMatch = allText.match(/@(?:[a-zA-Z][a-zA-Z0-9_]{3,30})/);
|
||||
if (tgMatch) {
|
||||
result.telegram = tgMatch[0];
|
||||
}
|
||||
|
||||
// Name patterns — "меня зовут X", "я X", "это X"
|
||||
const namePatterns = [
|
||||
/(?:меня зовут|зовут меня|я\s+—?\s*|это\s+)([А-ЯЁA-Z][а-яёa-z]+(?:\s+[А-ЯЁA-Z][а-яёa-z]+){0,2})/,
|
||||
/(?:my name is|i am|i\'m)\s+([A-Z][a-z]+(?:\s+[A-Z][a-z]+){0,2})/i,
|
||||
@@ -71,14 +83,12 @@ function extractLeadData(messages: ChatMessage[]): {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Simple customer profile generation
|
||||
function generateCustomerProfile(messages: ChatMessage[]): string {
|
||||
const totalMessages = messages.length;
|
||||
const userMessages = messages.filter((m) => m.role === 'user');
|
||||
const lastFew = userMessages.slice(-5).map((m) => m.content);
|
||||
const allText = lastFew.join(' ').toLowerCase();
|
||||
|
||||
// Intent detection
|
||||
let intent = 'general_inquiry';
|
||||
if (/цен[аыуе]|стоимость|price|how much|сколько/.test(allText)) intent = 'price_inquiry';
|
||||
else if (/доставк|shipping|достав/.test(allText)) intent = 'delivery_inquiry';
|
||||
@@ -86,7 +96,6 @@ function generateCustomerProfile(messages: ChatMessage[]): string {
|
||||
else if (/помощь|help|поддержк|support/.test(allText)) intent = 'support_request';
|
||||
else if (/отзыв|review|проблем|баг|не работ/.test(allText)) intent = 'complaint';
|
||||
|
||||
// Interest detection
|
||||
const interests: string[] = [];
|
||||
if (/биткоин|bitcoin|btc/.test(allText)) interests.push('Bitcoin');
|
||||
if (/ethereum|eth/.test(allText)) interests.push('Ethereum');
|
||||
@@ -94,7 +103,6 @@ function generateCustomerProfile(messages: ChatMessage[]): string {
|
||||
if (/usdt|tether/.test(allText)) interests.push('USDT');
|
||||
if (/кошел[ьеьк]|wallet/.test(allText)) interests.push('Wallets');
|
||||
|
||||
// Sentiment (very simple)
|
||||
const positiveWords = /спасибо|thanks|отлично|хорошо|great|good|класс|круто/;
|
||||
const negativeWords = /плох|бед|ужас|термин|проблем|ошибк|не работает|bad|awful/;
|
||||
let sentiment: string;
|
||||
@@ -102,7 +110,6 @@ function generateCustomerProfile(messages: ChatMessage[]): string {
|
||||
else if (positiveWords.test(allText)) sentiment = 'positive';
|
||||
else sentiment = 'neutral';
|
||||
|
||||
// Readiness
|
||||
let readiness: string;
|
||||
if (intent === 'purchase_intent') readiness = 'hot';
|
||||
else if (intent === 'price_inquiry') readiness = 'warm';
|
||||
@@ -120,20 +127,74 @@ function generateCustomerProfile(messages: ChatMessage[]): string {
|
||||
return JSON.stringify(profile);
|
||||
}
|
||||
|
||||
// ── Ollama Cloud API call (OpenAI-compatible) ──
|
||||
async function callOllama(
|
||||
messages: { role: string; content: string }[],
|
||||
endpoint: string,
|
||||
apiKey: string,
|
||||
model: string,
|
||||
temperature: number,
|
||||
maxTokens: number,
|
||||
): Promise<string> {
|
||||
const res = await fetch(endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model,
|
||||
messages,
|
||||
temperature,
|
||||
max_tokens: maxTokens,
|
||||
stream: false,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const text = await res.text().catch(() => '');
|
||||
throw new Error(`Ollama API ${res.status}: ${text}`);
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
return data?.choices?.[0]?.message?.content || 'Извините, не удалось получить ответ.';
|
||||
}
|
||||
|
||||
// ── z-ai-web-dev-sdk fallback ──
|
||||
async function callZaiSdk(
|
||||
messages: { role: string; content: string }[],
|
||||
temperature: number,
|
||||
maxTokens: number,
|
||||
): Promise<string> {
|
||||
const { ZAI } = await import('z-ai-web-dev-sdk');
|
||||
const zai = await ZAI.create();
|
||||
const result = await zai.chat.completions.create({
|
||||
messages,
|
||||
temperature,
|
||||
max_tokens: maxTokens,
|
||||
thinking: { type: 'disabled' as const },
|
||||
});
|
||||
return result?.choices?.[0]?.message?.content || 'Извините, не удалось получить ответ.';
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { sessionId, message, telegramId } = body as {
|
||||
const { sessionId, message, telegramId, language: userLang } = body as {
|
||||
sessionId: string;
|
||||
message: string;
|
||||
telegramId?: string;
|
||||
language?: string;
|
||||
};
|
||||
|
||||
if (!sessionId || !message) {
|
||||
return NextResponse.json({ error: 'Missing sessionId or message' }, { status: 400 });
|
||||
}
|
||||
|
||||
// Load chatbot config with cache
|
||||
// Normalise language
|
||||
const language = userLang?.toLowerCase()?.slice(0, 2) || 'en';
|
||||
|
||||
// Load chatbot config
|
||||
const config = await getChatbotConfig();
|
||||
const enabled = getConfig(config, 'chatbot_enabled', 'false');
|
||||
if (enabled !== 'true') {
|
||||
@@ -153,11 +214,19 @@ export async function POST(request: NextRequest) {
|
||||
} catch {
|
||||
existingMessages = [];
|
||||
}
|
||||
// Update language if changed
|
||||
if (session.language !== language) {
|
||||
await db.chatSession.update({
|
||||
where: { id: session.id },
|
||||
data: { language },
|
||||
});
|
||||
}
|
||||
} else {
|
||||
session = await db.chatSession.create({
|
||||
data: {
|
||||
sessionId,
|
||||
telegramId: telegramId || null,
|
||||
language,
|
||||
messages: JSON.stringify([]),
|
||||
isActive: true,
|
||||
},
|
||||
@@ -182,7 +251,7 @@ export async function POST(request: NextRequest) {
|
||||
};
|
||||
existingMessages.push(userMsg);
|
||||
|
||||
// Build system prompt
|
||||
// ── Build system prompt ──
|
||||
const systemPrompt = getConfig(config, 'chatbot_system_prompt', DEFAULTS.chatbot_system_prompt);
|
||||
const knowledgeBase = getConfig(config, 'chatbot_knowledge_base', '');
|
||||
const sleepMode = getConfig(config, 'chatbot_sleep_mode', 'false');
|
||||
@@ -190,9 +259,19 @@ export async function POST(request: NextRequest) {
|
||||
const temperature = parseFloat(getConfig(config, 'chatbot_temperature', '0.7'));
|
||||
const maxTokens = parseInt(getConfig(config, 'chatbot_max_tokens', '1024'), 10);
|
||||
const maxHistory = parseInt(getConfig(config, 'chatbot_max_history', '20'), 10);
|
||||
const provider = getConfig(config, 'chatbot_provider', 'ollama');
|
||||
const apiEndpoint = getConfig(config, 'chatbot_api_endpoint', DEFAULTS.chatbot_api_endpoint);
|
||||
const apiKey = getConfig(config, 'chatbot_api_key', '');
|
||||
const model = getConfig(config, 'chatbot_model', 'llama3.1:8b');
|
||||
|
||||
let fullSystemPrompt = systemPrompt;
|
||||
|
||||
// Language instruction
|
||||
const langInstruction = LANGUAGE_INSTRUCTIONS[language];
|
||||
if (langInstruction) {
|
||||
fullSystemPrompt = langInstruction + '\n\n' + fullSystemPrompt;
|
||||
}
|
||||
|
||||
if (knowledgeBase) {
|
||||
fullSystemPrompt += '\n\n--- База знаний ---\n' + knowledgeBase;
|
||||
}
|
||||
@@ -209,11 +288,11 @@ export async function POST(request: NextRequest) {
|
||||
fullSystemPrompt += '\n\n--- Профиль клиента ---\n' + profileStr;
|
||||
}
|
||||
} catch {
|
||||
// ignore parse error
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
// Catalog context — fetch some products for context
|
||||
// Catalog context
|
||||
try {
|
||||
const products = await db.product.findMany({
|
||||
where: { quantityInStock: { gt: 0 } },
|
||||
@@ -227,17 +306,17 @@ export async function POST(request: NextRequest) {
|
||||
fullSystemPrompt += '\n\n--- Каталог товаров ---\n' + catalogStr;
|
||||
}
|
||||
} catch {
|
||||
// ignore catalog fetch errors
|
||||
// ignore
|
||||
}
|
||||
|
||||
// Sleep mode
|
||||
// Sleep mode override
|
||||
if (sleepMode === 'true') {
|
||||
fullSystemPrompt =
|
||||
`ВНИМАНИЕ: Режим сна включён. Тебе нужно отвечать ТОЛЬКО следующим сообщением: "${sleepMessage}". Не отвечай ни на какие вопросы, просто отправляй это сообщение.\n\n` +
|
||||
`ВНИМАНИЕ: Режим сна включён. Отвечай ТОЛЬКО следующим сообщением: "${sleepMessage}". Не отвечай ни на какие вопросы, просто отправляй это сообщение.\n\n` +
|
||||
fullSystemPrompt;
|
||||
}
|
||||
|
||||
// Build history messages (limited)
|
||||
// Build history messages
|
||||
const historySlice = existingMessages.slice(-(maxHistory * 2));
|
||||
const historyMessages = historySlice.map((m) => ({
|
||||
role: m.role,
|
||||
@@ -249,25 +328,23 @@ export async function POST(request: NextRequest) {
|
||||
...historyMessages,
|
||||
];
|
||||
|
||||
// Call LLM via z-ai-web-dev-sdk
|
||||
// ── Call LLM ──
|
||||
let reply: string;
|
||||
try {
|
||||
const { ZAI } = await import('z-ai-web-dev-sdk');
|
||||
const zai = await ZAI.create();
|
||||
const result = await zai.functions.invoke('llm_chat', {
|
||||
messages: apiMessages,
|
||||
temperature,
|
||||
max_tokens: maxTokens,
|
||||
});
|
||||
reply = result?.content || result?.reply || result?.text || 'Извините, не удалось получить ответ.';
|
||||
if (provider === 'ollama' && apiKey) {
|
||||
reply = await callOllama(apiMessages, apiEndpoint, apiKey, model, temperature, maxTokens);
|
||||
} else {
|
||||
reply = await callZaiSdk(apiMessages, temperature, maxTokens);
|
||||
}
|
||||
if (typeof reply !== 'string') {
|
||||
reply = JSON.stringify(reply);
|
||||
}
|
||||
} catch (llmError) {
|
||||
console.error('LLM call failed:', llmError);
|
||||
reply = sleepMode === 'true'
|
||||
? sleepMessage
|
||||
: 'Извините, произошла техническая ошибка. Попробуйте написать позже.';
|
||||
reply =
|
||||
sleepMode === 'true'
|
||||
? sleepMessage
|
||||
: 'Извините, произошла техническая ошибка. Попробуйте написать позже.';
|
||||
}
|
||||
|
||||
// Save assistant reply
|
||||
@@ -279,11 +356,10 @@ export async function POST(request: NextRequest) {
|
||||
existingMessages.push(assistantMsg);
|
||||
|
||||
// Extract lead data
|
||||
const allMessages = [...existingMessages];
|
||||
const leadData = extractLeadData(allMessages);
|
||||
const leadData = extractLeadData(existingMessages);
|
||||
|
||||
// Generate customer profile
|
||||
const profile = generateCustomerProfile(allMessages);
|
||||
const profile = generateCustomerProfile(existingMessages);
|
||||
|
||||
// Update session
|
||||
await db.chatSession.update({
|
||||
@@ -299,17 +375,13 @@ export async function POST(request: NextRequest) {
|
||||
let leadId = session.leadId;
|
||||
|
||||
if (leadData.name || leadData.phone || leadData.email || leadData.telegram || telegramId) {
|
||||
// Try to find existing lead by telegramId first
|
||||
let lead = telegramId
|
||||
? await db.lead.findUnique({ where: { telegramId } })
|
||||
: null;
|
||||
let lead = telegramId ? await db.lead.findUnique({ where: { telegramId } }) : null;
|
||||
|
||||
if (!lead && leadId) {
|
||||
lead = await db.lead.findUnique({ where: { id: leadId } });
|
||||
}
|
||||
|
||||
if (lead) {
|
||||
// Update existing lead
|
||||
const updateData: Record<string, unknown> = { updatedAt: new Date() };
|
||||
if (leadData.name && !lead.name) updateData.name = leadData.name;
|
||||
if (leadData.phone && !lead.phone) updateData.phone = leadData.phone;
|
||||
@@ -317,13 +389,9 @@ export async function POST(request: NextRequest) {
|
||||
if (leadData.telegram && !lead.telegram) updateData.telegram = leadData.telegram;
|
||||
if (telegramId && !lead.telegramId) updateData.telegramId = telegramId;
|
||||
|
||||
await db.lead.update({
|
||||
where: { id: lead.id },
|
||||
data: updateData,
|
||||
});
|
||||
await db.lead.update({ where: { id: lead.id }, data: updateData });
|
||||
leadId = lead.id;
|
||||
} else {
|
||||
// Create new lead
|
||||
const newLead = await db.lead.create({
|
||||
data: {
|
||||
telegramId: telegramId || null,
|
||||
@@ -336,7 +404,6 @@ export async function POST(request: NextRequest) {
|
||||
});
|
||||
leadId = newLead.id;
|
||||
|
||||
// Link session to lead
|
||||
await db.chatSession.update({
|
||||
where: { id: session.id },
|
||||
data: { leadId: newLead.id },
|
||||
@@ -346,7 +413,6 @@ export async function POST(request: NextRequest) {
|
||||
leadId = session.leadId;
|
||||
}
|
||||
|
||||
// Parse profile for response
|
||||
let parsedProfile;
|
||||
try {
|
||||
parsedProfile = JSON.parse(profile);
|
||||
|
||||
@@ -16,14 +16,13 @@ const TABS = [
|
||||
type TabValue = (typeof TABS)[number]["value"];
|
||||
|
||||
function resolveInitialTab(): TabValue {
|
||||
const hash = window.location.hash.slice(1); // e.g. /catalog?tab=categories
|
||||
const hash = window.location.hash.slice(1);
|
||||
const params = hash.split("?")[1] || "";
|
||||
const match = params.match(/tab=(\w+)/);
|
||||
if (match) {
|
||||
const v = match[1];
|
||||
if (TABS.some((t) => t.value === v)) return v as TabValue;
|
||||
}
|
||||
// also support /catalog/categories, /catalog/locations
|
||||
const path = hash.split("?")[0];
|
||||
if (path === "/catalog/categories") return "categories";
|
||||
if (path === "/catalog/locations") return "locations";
|
||||
@@ -33,7 +32,6 @@ function resolveInitialTab(): TabValue {
|
||||
export function CatalogHub() {
|
||||
const [activeTab, setActiveTab] = useState<TabValue>("products");
|
||||
|
||||
// Sync from hash on mount / hashchange
|
||||
useEffect(() => {
|
||||
const sync = () => {
|
||||
setActiveTab(resolveInitialTab());
|
||||
@@ -46,7 +44,6 @@ export function CatalogHub() {
|
||||
const handleTabChange = (value: string) => {
|
||||
const tab = value as TabValue;
|
||||
setActiveTab(tab);
|
||||
// Update hash without full page re-render
|
||||
const base = "/catalog";
|
||||
if (tab === "products") {
|
||||
window.location.hash = base;
|
||||
@@ -71,27 +68,27 @@ export function CatalogHub() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Tabs value={activeTab} onValueChange={handleTabChange} className="space-y-4">
|
||||
<TabsList className="grid w-full max-w-md grid-cols-3">
|
||||
<Tabs value={activeTab} onValueChange={handleTabChange} className="w-full">
|
||||
<TabsList className="inline-flex h-10 w-full max-w-lg bg-muted p-1 rounded-lg">
|
||||
{TABS.map((tab) => (
|
||||
<TabsTrigger
|
||||
key={tab.value}
|
||||
value={tab.value}
|
||||
className="gap-2 data-[state=active]:shadow-sm"
|
||||
className="flex-1 flex items-center justify-center gap-2 px-3 py-2 rounded-md text-sm font-medium transition-all data-[state=active]:bg-background data-[state=active]:shadow-sm data-[state=active]:text-foreground"
|
||||
>
|
||||
<tab.icon className="size-4" />
|
||||
<tab.icon className="size-4 shrink-0" />
|
||||
<span className="hidden sm:inline">{tab.label}</span>
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="products" className="mt-4">
|
||||
<TabsContent value="products" className="mt-6">
|
||||
<CatalogPage />
|
||||
</TabsContent>
|
||||
<TabsContent value="categories" className="mt-4">
|
||||
<TabsContent value="categories" className="mt-6">
|
||||
<CategoriesPage />
|
||||
</TabsContent>
|
||||
<TabsContent value="locations" className="mt-4">
|
||||
<TabsContent value="locations" className="mt-6">
|
||||
<LocationsPage />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
@@ -291,8 +291,6 @@ export function CatalogPage() {
|
||||
|
||||
// ─── Tree grouping ─────────────────────────────
|
||||
const getGroupedTree = () => {
|
||||
if (!tree) return {};
|
||||
|
||||
const countryMap = new Map<
|
||||
string,
|
||||
{
|
||||
@@ -308,6 +306,8 @@ export function CatalogPage() {
|
||||
}
|
||||
>();
|
||||
|
||||
if (!tree) return countryMap;
|
||||
|
||||
for (const loc of tree.locations) {
|
||||
if (!countryMap.has(loc.country))
|
||||
countryMap.set(loc.country, { cityMap: new Map() });
|
||||
|
||||
@@ -56,6 +56,7 @@ interface ChatbotSettings {
|
||||
chatbot_provider: string;
|
||||
chatbot_api_endpoint: string;
|
||||
chatbot_api_key: string;
|
||||
chatbot_model: string;
|
||||
}
|
||||
|
||||
const DEFAULTS: ChatbotSettings = {
|
||||
@@ -70,9 +71,10 @@ const DEFAULTS: ChatbotSettings = {
|
||||
chatbot_max_tokens: 1000,
|
||||
chatbot_max_history: 20,
|
||||
chatbot_knowledge_base: "",
|
||||
chatbot_provider: "openai",
|
||||
chatbot_api_endpoint: "",
|
||||
chatbot_provider: "ollama",
|
||||
chatbot_api_endpoint: "https://ollama.com/v1/chat/completions",
|
||||
chatbot_api_key: "",
|
||||
chatbot_model: "deepseek-v4-flash:preview",
|
||||
};
|
||||
|
||||
function SettingsSkeleton() {
|
||||
@@ -99,7 +101,24 @@ export function ChatbotSettingsPage() {
|
||||
const res = await fetch("/api/admin/chatbot");
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
setSettings({ ...DEFAULTS, ...data });
|
||||
const raw = data.settings || data;
|
||||
const parsed: ChatbotSettings = {
|
||||
...DEFAULTS,
|
||||
chatbot_enabled: raw.chatbot_enabled === "true",
|
||||
chatbot_sleep_mode: raw.chatbot_sleep_mode === "true",
|
||||
chatbot_sleep_message: raw.chatbot_sleep_message || DEFAULTS.chatbot_sleep_message,
|
||||
chatbot_system_prompt: raw.chatbot_system_prompt || DEFAULTS.chatbot_system_prompt,
|
||||
chatbot_welcome_message: raw.chatbot_welcome_message || "",
|
||||
chatbot_temperature: parseFloat(raw.chatbot_temperature) || 0.7,
|
||||
chatbot_max_tokens: parseInt(raw.chatbot_max_tokens, 10) || 1000,
|
||||
chatbot_max_history: parseInt(raw.chatbot_max_history, 10) || 20,
|
||||
chatbot_knowledge_base: raw.chatbot_knowledge_base || "",
|
||||
chatbot_provider: raw.chatbot_provider || "ollama",
|
||||
chatbot_api_endpoint: raw.chatbot_api_endpoint || "",
|
||||
chatbot_api_key: raw.chatbot_api_key || "",
|
||||
chatbot_model: raw.chatbot_model || "deepseek-v4-flash:preview",
|
||||
};
|
||||
setSettings(parsed);
|
||||
}
|
||||
} catch {
|
||||
toast.error("Ошибка загрузки настроек");
|
||||
@@ -480,10 +499,47 @@ export function ChatbotSettingsPage() {
|
||||
onChange={(e) =>
|
||||
update("chatbot_api_endpoint", e.target.value)
|
||||
}
|
||||
placeholder="https://api.openai.com/v1"
|
||||
placeholder="https://api.ollama.com/v1/chat/completions"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="model" className="text-sm font-medium">
|
||||
Модель
|
||||
</Label>
|
||||
<Select
|
||||
value={settings.chatbot_model}
|
||||
onValueChange={(v) => update("chatbot_model", v)}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Выберите модель" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="deepseek-v4-flash:preview">DeepSeek V4 Flash</SelectItem>
|
||||
<SelectItem value="deepseek-v4-pro">DeepSeek V4 Pro</SelectItem>
|
||||
<SelectItem value="deepseek-v4-flash:0731">DeepSeek V4 Flash 0731</SelectItem>
|
||||
<SelectItem value="kimi-k3">Kimi K3</SelectItem>
|
||||
<SelectItem value="kimi-k2.6">Kimi K2.6</SelectItem>
|
||||
<SelectItem value="kimi-k2.7-code">Kimi K2.7 Code</SelectItem>
|
||||
<SelectItem value="gemma4:31b">Gemma 4 31B</SelectItem>
|
||||
<SelectItem value="gpt-oss:120b">GPT-OSS 120B</SelectItem>
|
||||
<SelectItem value="gpt-oss:20b">GPT-OSS 20B</SelectItem>
|
||||
<SelectItem value="mistral-large-3:675b">Mistral Large 3 675B</SelectItem>
|
||||
<SelectItem value="nemotron-3-ultra">Nemotron 3 Ultra</SelectItem>
|
||||
<SelectItem value="nemotron-3-super">Nemotron 3 Super</SelectItem>
|
||||
<SelectItem value="minimax-m3">MiniMax M3</SelectItem>
|
||||
<SelectItem value="minimax-m2.7">MiniMax M2.7</SelectItem>
|
||||
<SelectItem value="qwen3.5:397b">Qwen 3.5 397B</SelectItem>
|
||||
<SelectItem value="glm-5.2">GLM 5.2</SelectItem>
|
||||
<SelectItem value="glm-5.1">GLM 5.1</SelectItem>
|
||||
<SelectItem value="nemotron-3-nano:30b">Nemotron 3 Nano 30B</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Доступные модели Ollama Cloud. Для Custom — введите вручную.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="api_key" className="text-sm font-medium">
|
||||
API Key
|
||||
@@ -495,7 +551,7 @@ export function ChatbotSettingsPage() {
|
||||
onChange={(e) =>
|
||||
update("chatbot_api_key", e.target.value)
|
||||
}
|
||||
placeholder="sk-..."
|
||||
placeholder="b364c..."
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Ключ хранится зашифрованным. При отображении маскируется.
|
||||
|
||||
@@ -9,8 +9,6 @@ import {
|
||||
Wallet,
|
||||
ShoppingCart,
|
||||
FileText,
|
||||
Tag,
|
||||
MapPin,
|
||||
Settings,
|
||||
Languages,
|
||||
AlertTriangle,
|
||||
@@ -19,6 +17,7 @@ import {
|
||||
Shield,
|
||||
Bot,
|
||||
Target,
|
||||
FolderTree,
|
||||
} from "lucide-react";
|
||||
import {
|
||||
Sidebar,
|
||||
@@ -48,9 +47,7 @@ const mainNav = [
|
||||
];
|
||||
|
||||
const catalogNav = [
|
||||
{ title: "Товары", href: "/catalog", icon: Package, shortcut: "6" },
|
||||
{ title: "Категории", href: "/catalog?tab=categories", icon: Tag, shortcut: "7" },
|
||||
{ title: "Локации", href: "/catalog?tab=locations", icon: MapPin, shortcut: "8" },
|
||||
{ title: "Каталог товаров", href: "/catalog", icon: FolderTree, shortcut: "6" },
|
||||
];
|
||||
|
||||
const automationNav = [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState, useEffect, Fragment } from "react";
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbEllipsis,
|
||||
@@ -41,11 +41,9 @@ function parseHash(hash: string): Crumb[] {
|
||||
return crumbs;
|
||||
}
|
||||
|
||||
// Build parent href incrementally
|
||||
let href = "";
|
||||
for (let i = 0; i < segments.length; i++) {
|
||||
href += "/" + segments[i];
|
||||
const isLast = i === segments.length - 1;
|
||||
const label = pageLabels[segments[i]] || segments[i];
|
||||
crumbs.push({ label, href });
|
||||
}
|
||||
@@ -69,53 +67,57 @@ export function AppBreadcrumbs() {
|
||||
|
||||
return (
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
{/* Desktop: show all breadcrumbs */}
|
||||
{/* Desktop: show all breadcrumbs */}
|
||||
<BreadcrumbList className="hidden sm:flex">
|
||||
{crumbs.map((crumb, index) => {
|
||||
const isLast = index === crumbs.length - 1;
|
||||
return (
|
||||
<BreadcrumbItem key={crumb.href} className="hidden sm:inline-flex">
|
||||
{isLast ? (
|
||||
<BreadcrumbPage>{crumb.label}</BreadcrumbPage>
|
||||
) : (
|
||||
<BreadcrumbLink
|
||||
href="#"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
window.location.hash = crumb.href;
|
||||
}}
|
||||
>
|
||||
{crumb.label}
|
||||
</BreadcrumbLink>
|
||||
)}
|
||||
<Fragment key={crumb.href}>
|
||||
<BreadcrumbItem>
|
||||
{isLast ? (
|
||||
<BreadcrumbPage>{crumb.label}</BreadcrumbPage>
|
||||
) : (
|
||||
<BreadcrumbLink
|
||||
href="#"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
window.location.hash = crumb.href;
|
||||
}}
|
||||
>
|
||||
{crumb.label}
|
||||
</BreadcrumbLink>
|
||||
)}
|
||||
</BreadcrumbItem>
|
||||
{!isLast && <BreadcrumbSeparator />}
|
||||
</BreadcrumbItem>
|
||||
</Fragment>
|
||||
);
|
||||
})}
|
||||
</BreadcrumbList>
|
||||
|
||||
{/* Mobile: show only last 2 breadcrumbs with ellipsis */}
|
||||
{/* Mobile: show last 2 breadcrumbs with ellipsis */}
|
||||
<BreadcrumbList className="flex sm:hidden">
|
||||
{crumbs.length > 2 && (
|
||||
<BreadcrumbItem className="sm:hidden">
|
||||
<BreadcrumbEllipsis />
|
||||
<>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbEllipsis />
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
</BreadcrumbItem>
|
||||
</>
|
||||
)}
|
||||
{crumbs.length >= 2 && (
|
||||
<BreadcrumbItem className="sm:hidden">
|
||||
<BreadcrumbLink
|
||||
href="#"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
const href = crumbs[crumbs.length - 2].href;
|
||||
window.location.hash = href;
|
||||
}}
|
||||
>
|
||||
{crumbs[crumbs.length - 2].label}
|
||||
</BreadcrumbLink>
|
||||
<BreadcrumbSeparator />
|
||||
</BreadcrumbItem>
|
||||
)}
|
||||
<BreadcrumbItem className="sm:hidden">
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink
|
||||
href="#"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
const href = crumbs.length > 1 ? crumbs[crumbs.length - 2].href : "/";
|
||||
window.location.hash = href;
|
||||
}}
|
||||
>
|
||||
{crumbs.length > 1 ? crumbs[crumbs.length - 2].label : "Home"}
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
<BreadcrumbSeparator />
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbPage>{crumbs[crumbs.length - 1].label}</BreadcrumbPage>
|
||||
</BreadcrumbItem>
|
||||
</BreadcrumbList>
|
||||
|
||||
647
tool-results/read_1786098853590_868a592a6c82.txt
Normal file
647
tool-results/read_1786098853590_868a592a6c82.txt
Normal file
@@ -0,0 +1,647 @@
|
||||
1→# Telegram Shop Admin Panel — Worklog
|
||||
2→
|
||||
3→---
|
||||
4→## Current Project Status (2026-08-06 — AI Chatbot + Leads + Sleep Mode + Matrix BG Sprint)
|
||||
5→
|
||||
6→### Assessment
|
||||
7→
|
||||
8→**Code Quality:**
|
||||
9→- ✅ ESLint: 0 errors, 0 warnings
|
||||
10→- ✅ All 13 original pages preserved and working
|
||||
11→- ✅ 2 new pages added (AI Chatbot Settings, Leads)
|
||||
12→- ✅ 8 new API routes (chatbot, leads, chat, operator)
|
||||
13→- ✅ 3 new Prisma models (ChatSession, Lead, SiteSetting)
|
||||
14→- ✅ Matrix Rain CSS background on login page
|
||||
15→- ✅ Dark theme compatible, Russian UI
|
||||
16→
|
||||
17→**Files:** 140+ source files
|
||||
18→- 15 page components (added AI Chatbot, Leads)
|
||||
19→- 48+ API route handlers
|
||||
20→- 15 shared/layout components
|
||||
21→- 15 Prisma models
|
||||
22→
|
||||
23→**New Features This Round:**
|
||||
24→1. **AI Chatbot Settings** (`#/chatbot`) — 4-tab configuration page
|
||||
25→ - General: enabled toggle, sleep mode toggle + message, system prompt, welcome message
|
||||
26→ - AI Parameters: temperature slider, max tokens, max history per client
|
||||
27→ - Knowledge Base: dictionary/lexicon textarea for product info & FAQ
|
||||
28→ - Provider: OpenAI/DeepSeek/OpenRouter/Ollama/Custom, API endpoint & key
|
||||
29→2. **Leads Management** (`#/leads`) — full leads & conversations page
|
||||
30→ - Table with search, status filters (new/contacted/qualified/lost/spam)
|
||||
31→ - AI profile card (intent, interests, sentiment, readiness, budget)
|
||||
32→ - Chat session viewer with message bubbles
|
||||
33→ - Operator takeover (connect/disconnect) with audit log
|
||||
34→ - Notes editing, quick status change
|
||||
35→3. **Sleep Mode** — when enabled, /start shows AI chat instead of catalog
|
||||
36→ - Bot informs user shop is restocking
|
||||
37→ - Collects contacts for future notification
|
||||
38→4. **Chat API** (`POST /api/chat`) — TG bot integration
|
||||
39→ - Session management, LLM via z-ai-web-dev-sdk
|
||||
40→ - Automatic lead extraction (name, phone, email, telegram)
|
||||
41→ - Customer profile generation (intent, interests, sentiment, readiness)
|
||||
42→ - Catalog context injection into prompts
|
||||
43→ - Individual conversation history per client (configurable depth)
|
||||
44→5. **Matrix Rain Background** — CSS-only animation on login page
|
||||
45→ - Two layers of falling characters at very low opacity (0.025-0.06)
|
||||
46→ - Dark mode adaptive (brighter in dark theme)
|
||||
47→6. **Documentation** — comprehensive docs/admin-nextjs-guide.md rewrite
|
||||
48→ - All 48+ API routes documented
|
||||
49→ - Full data model description
|
||||
50→ - AI bot architecture, profiling, operator flow documented
|
||||
51→
|
||||
52→**New API Routes:**
|
||||
53→- `GET/PUT /api/admin/chatbot` — chatbot settings CRUD
|
||||
54→- `POST /api/chat` — chat endpoint for TG bot
|
||||
55→- `GET /api/leads/bulk` — paginated leads list
|
||||
56→- `GET/PUT /api/leads/[id]` — lead detail/update
|
||||
57→- `GET /api/leads/[id]/sessions` — chat sessions for a lead
|
||||
58→- `POST /api/operator` — operator connect/disconnect
|
||||
59→
|
||||
60→**New DB Models:**
|
||||
61→- `ChatSession` — chat sessions with messages JSON, customer profile, operator state
|
||||
62→- `Lead` — extracted leads with AI score, status, custom fields
|
||||
63→- `SiteSetting` — key-value settings storage for chatbot config
|
||||
64→
|
||||
65→### Unresolved Issues / Risks
|
||||
66→1. **Sandbox OOM** — Dev server needs ~1.5GB, standalone ~50MB. Use production build.
|
||||
67→2. **Settings import** — Endpoint returns 'not yet implemented'
|
||||
68→3. **Photo uploads** — No multipart API yet
|
||||
69→4. **SSE live updates** — Dashboard refreshes but no push
|
||||
70→5. **Client-side sort** — Sort indicator shown but only sorts current page
|
||||
71→6. **Dashboard sparklines** — Use random data, no real history
|
||||
72→7. **Multi-admin identity** — Audit log stores role string, not admin ID
|
||||
73→
|
||||
74→### Priority Recommendations for Next Phase
|
||||
75→1. **HIGH**: Dockerfile + docker-compose.yml for ARM deployment
|
||||
76→2. **HIGH**: Test on real ARM device
|
||||
77→3. **HIGH**: Connect to Gitea, push changes
|
||||
78→4. **MEDIUM**: Implement settings import logic
|
||||
79→5. **MEDIUM**: Product photo upload API
|
||||
80→6. **MEDIUM**: SSE endpoint for real-time dashboard
|
||||
81→7. **MEDIUM**: Server-side sort for all list APIs
|
||||
82→8. **LOW**: Real KPI history for sparklines
|
||||
83→9. **LOW**: Multi-admin users table
|
||||
84→
|
||||
85→
|
||||
86→---
|
||||
87→Task ID: 10
|
||||
88→Agent: Main Coordinator + 3 subagents
|
||||
89→Task: AI Chatbot, Leads, Sleep Mode, Matrix Background, Documentation
|
||||
90→
|
||||
91→Work Log:
|
||||
92→- Studied qrgeo project (chat, leads, chatbot admin, schema, AdminLeadsView)
|
||||
93→- Added 3 Prisma models: ChatSession, Lead, SiteSetting
|
||||
94→- Created 8 API routes (chatbot config, chat, leads, operator)
|
||||
95→- Created chatbot settings page (4 tabs: General, AI Params, Knowledge Base, Provider)
|
||||
96→- Created leads management page (table, chat viewer, operator takeover, AI profiles)
|
||||
97→- Added Matrix Rain CSS background to login page
|
||||
98→- Updated sidebar navigation with AI Chatbot and Leads items
|
||||
99→- Updated page.tsx routing for new pages
|
||||
100→- Rewrote docs/admin-nextjs-guide.md (15 models, 48+ API routes, full architecture)
|
||||
101→- Updated worklog.md
|
||||
102→
|
||||
103→Stage Summary:
|
||||
104→- 8 new API routes, 2 new page components, 3 new DB models
|
||||
105→- 1 shared library (chatbot-config.ts)
|
||||
106→- ESLint: 0 errors, 0 warnings
|
||||
107→- Total: 140+ source files, 48+ API routes, 15 Prisma models
|
||||
108→
|
||||
109→
|
||||
110→### Assessment
|
||||
111→
|
||||
112→**Code Quality:**
|
||||
113→- ✅ ESLint: 0 errors, 0 warnings
|
||||
114→- ✅ Server compiles successfully (GET / 200, 8.0s compile)
|
||||
115→- ✅ All navigation uses `window.location.hash`
|
||||
116→- ✅ All 13 page components use named exports, `@/` imports, `sonner` toasts
|
||||
117→- ✅ Dark-theme-compatible badge colors (opacity-based)
|
||||
118→- ✅ ErrorBoundary wrapping all page renders
|
||||
119→- ✅ Auth: secure cookie flag in production, no hardcoded secrets
|
||||
120→- ✅ Sticky footer, keyboard shortcuts (1-9), focus-visible ring, sticky table headers
|
||||
121→- ✅ Branded loading screen with progress bar animation
|
||||
122→
|
||||
123→**Files:** 128+ source files
|
||||
124→- 13 page components (dashboard, catalog, users×2, wallets, purchases, audit, categories, locations, settings, locales, seed)
|
||||
125→- 40 API route handlers (3 new: batch-status×2, product clone)
|
||||
126→- 15 shared/layout components + 3 shared utility components
|
||||
127→- 3 hooks (use-debounce, use-mobile, use-keyboard-shortcuts)
|
||||
128→- 1 store (auth-store), 1 Prisma schema (12 models)
|
||||
129→- 48 shadcn/ui components
|
||||
130→
|
||||
131→**Bug Fixes This Round (9 bugs fixed):**
|
||||
132→1. **[CRITICAL] Settings PUT no-op** → Now actually persists to in-memory SETTINGS object with key validation
|
||||
133→2. **[HIGH] Audit userId filter false matches** → Added trailing comma in JSON substring match (`"userId":${id},`) prevents ID=1 matching ID=10
|
||||
134→3. **[HIGH] Product DELETE no safety check** → Now checks `purchaseCount` before deleting, returns 400 with descriptive error
|
||||
135→4. **[HIGH] CSV export injection** → Added proper `escapeCsv()` function that doubles internal quotes and wraps all fields
|
||||
136→5. **[HIGH] Rate limiter memory leak** → Added `setInterval` cleanup every 10 minutes for expired entries
|
||||
137→6. **[HIGH] openProductModal missing res.ok** → Now checks `treeRes.ok` and `locRes.ok` before parsing JSON
|
||||
138→7. **[MEDIUM] Quick Actions seed visible to all** → Now gated by `role === 'super_admin'`
|
||||
139→8. **[MEDIUM] Command palette duplicate nav** → "Clear Data" now navigates to `#/seed?action=clear`
|
||||
140→9. **[LOW] "use server" in API route** → Removed from purchases/[id]/route.ts
|
||||
141→
|
||||
142→**New Features This Round:**
|
||||
143→1. **Users batch actions** — Checkbox column, Select All, floating action bar with Ban/Unban, batch API route
|
||||
144→2. **Purchases batch actions** — Checkbox column, Select All, floating action bar with Approve/Cancel, batch API route
|
||||
145→3. **Dashboard activity feed overhaul** — Uses recentActivity from dashboard API, 15 action-type icons, color-coded badges, relative time, staggered animations
|
||||
146→4. **Product clone** — Duplicate button (Copy icon) on each product row, creates copy with "(Copy)" suffix
|
||||
147→5. **User detail activity timeline** — Vertical timeline with colored dots, expandable details, relative time, staggered entry
|
||||
148→6. **Wallets balance summary** — 3 glass-card mini cards (Total Balance, Total Wallets, Active Wallets %) in Owner Summary tab
|
||||
149→
|
||||
150→**Styling Improvements This Round:**
|
||||
151→1. **~265 lines of new CSS** — glass-card, kpi-shimmer, count-up, colon-pulse, gradient borders, alternate-rows, table-header-gradient, glow effects, noise texture, page-section-enter
|
||||
152→2. **Sidebar polish** — Active nav 2px left-border accent, icon hover transitions, pulsing dot on Purchases, polished footer
|
||||
153→3. **Header polish** — Gradient bottom border, backdrop-blur translucent header, pulsing colon in clock
|
||||
154→4. **Footer polish** — Gradient top border, hover transitions, improved spacing and text hierarchy
|
||||
155→5. **Dashboard KPIs** — Shimmer hover effect, stat-value formatting, chart card icons
|
||||
156→6. **Table improvements** — Alternating row colors, first-column left accent, gradient headers on users/purchases
|
||||
157→
|
||||
158→**Completed Modifications & Verification:**
|
||||
159→- ✅ ESLint: 0 errors, 0 warnings after all changes
|
||||
160→- ✅ Compile: GET / 200 (8.0s compile, 321ms render)
|
||||
161→- ✅ 128+ source files, 40 API routes
|
||||
162→- ✅ All features from Rounds 1-5 preserved and working
|
||||
163→
|
||||
164→### Unresolved Issues / Risks
|
||||
165→1. **Sandbox OOM** — Dev server dies after compilation. Not a code bug. Production build recommended.
|
||||
166→2. **Photo uploads** — Product photo upload not implemented (no multipart API)
|
||||
167→3. **Real backend integration** — Standalone Prisma/SQLite, needs shared DB volume for Docker
|
||||
168→4. **SSE live updates** — Dashboard auto-refreshes but no push updates
|
||||
169→5. **Categories/Locations pagination** — Still fetches all data (client-side filter)
|
||||
170→6. **Settings import** — Endpoint returns 'not yet implemented'
|
||||
171→7. **No individual admin identity** — Audit log stores role string, not admin ID
|
||||
172→8. **Dashboard sparklines use random data** — No real historical data yet
|
||||
173→9. **Transactions API** — No date range or type filtering
|
||||
174→10. **Client-side sort conflicts with server-side pagination** — Sort indicator shown but only sorts current page
|
||||
175→
|
||||
176→### Priority Recommendations for Next Phase
|
||||
177→1. **HIGH**: Add production Dockerfile and docker-compose.yml
|
||||
178→2. **HIGH**: Test on real ARM device, fix any runtime errors
|
||||
179→3. **HIGH**: Connect to Gitea and push all changes
|
||||
180→4. **MEDIUM**: Implement actual settings import logic
|
||||
181→5. **MEDIUM**: Add photo upload API for products
|
||||
182→6. **MEDIUM**: Add SSE endpoint for real-time dashboard updates
|
||||
183→7. **MEDIUM**: Add server-side pagination to categories, locations APIs
|
||||
184→8. **MEDIUM**: Add date/filter params to transactions API
|
||||
185→9. **MEDIUM**: Fix client-side sort to use server-side sorting params
|
||||
186→10. **LOW**: Store historical KPI data for real sparklines
|
||||
187→11. **LOW**: Add admin users table for multi-admin identity
|
||||
188→
|
||||
189→
|
||||
190→---
|
||||
191→Task ID: 1-12 (initial build)
|
||||
192→Agent: Main Coordinator + 4 subagents
|
||||
193→Task: Full admin panel build from scratch
|
||||
194→
|
||||
195→Summary:
|
||||
196→- Prisma schema (11 tables), auth system (HMAC), app shell (sidebar/header)
|
||||
197→- 11 page components with 30+ API routes
|
||||
198→- Seed data identical to original project
|
||||
199→- Real i18n locale data (en/es/de)
|
||||
200→- Pushed to Gitea PR #132
|
||||
201→
|
||||
202→---
|
||||
203→Task ID: 5-a
|
||||
204→Agent: Styling Agent
|
||||
205→Task: Global CSS and login page styling overhaul
|
||||
206→
|
||||
207→Work Log:
|
||||
208→- Added custom scrollbar styling (thin, rounded, themed)
|
||||
209→- Added smooth transition classes for interactive elements
|
||||
210→- Added page-enter fade-in animation
|
||||
211→- Added card-hover lift effect
|
||||
212→- Added skeleton shimmer animation
|
||||
213→- Added subtle gradient mesh background to login
|
||||
214→- Added glass-morphism card effect to login
|
||||
215→- Added animated loading spinner to login button
|
||||
216→- Added keyboard shortcut hint
|
||||
217→
|
||||
218→Stage Summary:
|
||||
219→- globals.css: Added ~80 lines of custom CSS (scrollbars, animations, hover effects)
|
||||
220→- login/page.tsx: Complete visual redesign with gradient background, glass card, better typography
|
||||
221→- Both files pass ESLint
|
||||
222→
|
||||
223→---
|
||||
224→Task ID: 5-b
|
||||
225→Agent: Dashboard Agent
|
||||
226→Task: Dashboard styling and features overhaul
|
||||
227→
|
||||
228→Work Log:
|
||||
229→- Added refresh button with spin animation
|
||||
230→- Added auto-refresh toggle (30s interval)
|
||||
231→- Added last updated timestamp
|
||||
232→- Improved KPI cards with card-hover, left border accent, tabular-nums
|
||||
233→- Improved chart cards with card-hover, h-72
|
||||
234→- Added wallet count bar chart
|
||||
235→- Wrapped activity feed in proper Card
|
||||
236→
|
||||
237→Stage Summary:
|
||||
238→- dashboard-page.tsx: Enhanced with refresh controls, better styling, wallet chart
|
||||
239→- ESLint passes clean
|
||||
240→
|
||||
241→---
|
||||
242→Task ID: 5-c
|
||||
243→Agent: List Pages Agent
|
||||
244→Task: Improve styling and features for all list pages
|
||||
245→
|
||||
246→
|
||||
247→Work Log:
|
||||
248→- Added page-enter animation to all 5 list pages
|
||||
249→- Added subtitle descriptions with counts
|
||||
250→- Standardized table wrapper with max-h and rounded-lg border
|
||||
251→- Added font-mono text-xs to ID columns
|
||||
252→- Added whitespace-nowrap to status badge columns
|
||||
253→- Improved empty states with consistent pattern
|
||||
254→- Users page: numbered pagination with ellipsis
|
||||
255→- Purchases page: Tabs with per-status counts
|
||||
256→- Audit page: action type filter dropdown
|
||||
257→- Categories page: debounced search
|
||||
258→- Locations page: debounced search
|
||||
259→
|
||||
260→Stage Summary:
|
||||
261→- 5 page components enhanced with better styling and new features
|
||||
262→- ESLint passes clean
|
||||
263→
|
||||
264→---
|
||||
265→Task ID: 5-d
|
||||
266→Agent: Detail Pages Agent
|
||||
267→Task: Improve wallets and user-detail pages
|
||||
268→
|
||||
269→Work Log:
|
||||
270→- Added page-enter animation to both pages
|
||||
271→- Added search filter to wallets page
|
||||
272→- Added status filter badges to wallets page
|
||||
273→- Added back button and KPI summary cards to user detail
|
||||
274→- Added tabs (Purchases/Wallets/Activity) to user detail
|
||||
275→- Added audit log userId filtering support
|
||||
276→- Improved empty states
|
||||
277→- Improved record payment dialog spacing
|
||||
278→
|
||||
279→Stage Summary:
|
||||
280→- 2 page components significantly enhanced
|
||||
281→- 1 API route updated
|
||||
282→- ESLint passes clean
|
||||
283→
|
||||
284→---
|
||||
285→Task ID: 6-a (Round 2)
|
||||
286→Agent: Features Agent
|
||||
287→Task: Add notifications panel, quick actions, clock, enhanced command palette
|
||||
288→
|
||||
289→
|
||||
290→Work Log:
|
||||
291→- Created quick-actions.tsx
|
||||
292→- Added real-time clock to header
|
||||
293→- Enhanced command palette with footer, dividers, keyboard hints
|
||||
294→- Created notifications-panel.tsx
|
||||
295→- Integrated into admin-header.tsx
|
||||
296→
|
||||
297→Stage Summary:
|
||||
298→- 2 new components, 2 enhanced
|
||||
299→- ESLint passes clean
|
||||
300→
|
||||
301→---
|
||||
302→Task ID: 4-a
|
||||
303→Agent: Bug Fix Agent
|
||||
304→Task: 12 targeted bug fixes
|
||||
305→
|
||||
306→Work Log:
|
||||
307→- Fixed dark theme badge colors across wallets/user-detail
|
||||
308→- Fixed command palette role leak
|
||||
309→- Fixed notifications count mismatch
|
||||
310→- Fixed catalog page-enter + duplicate title
|
||||
311→- Fixed login role demotion fallback
|
||||
312→- Changed admin123 to changeme
|
||||
313→- Added secure cookie flag
|
||||
314→- Made logout async with try/catch
|
||||
315→- Added JSON export option
|
||||
316→- Removed duplicate page titles
|
||||
317→- Added purchase status management
|
||||
318→- Added ErrorBoundary
|
||||
319→
|
||||
320→Stage Summary:
|
||||
321→- 10 files modified
|
||||
322→- ESLint: 0 errors, 0 warnings
|
||||
323→
|
||||
324→---
|
||||
325→Task ID: 4-b
|
||||
326→Agent: Purchase Status Agent
|
||||
327→Task: Purchase approve/cancel with API + UI
|
||||
328→
|
||||
329→Stage Summary:
|
||||
330→- 1 new API route, 1 file modified
|
||||
331→- ESLint: 0 errors
|
||||
332→
|
||||
333→---
|
||||
334→Task ID: 4-c
|
||||
335→Agent: Filter Agent
|
||||
336→Task: Date range filtering + audit search
|
||||
337→
|
||||
338→Stage Summary:
|
||||
339→- 4 files modified
|
||||
340→- ESLint: 0 errors
|
||||
341→
|
||||
342→---
|
||||
343→Task ID: 4-d
|
||||
344→Agent: Shared Utilities Agent
|
||||
345→Task: Pagination, useDebounce, ErrorBoundary
|
||||
346→
|
||||
347→Stage Summary:
|
||||
348→- 3 new files, 3 modified
|
||||
349→- ESLint: 0 errors
|
||||
350→
|
||||
351→---
|
||||
352→Task ID: 5-e
|
||||
353→Agent: Header Polish Agent
|
||||
354→Task: Logout confirmation dialog
|
||||
355→
|
||||
356→Stage Summary:
|
||||
357→- 1 file modified
|
||||
358→- ESLint: 0 errors
|
||||
359→
|
||||
360→---
|
||||
361→Task ID: 6-a
|
||||
362→Agent: Dashboard Enhancement Agent
|
||||
363→Task: More KPIs, donut chart, recent purchases
|
||||
364→
|
||||
365→Stage Summary:
|
||||
366→- 2 files modified
|
||||
367→- ESLint: 0 errors
|
||||
368→
|
||||
369→---
|
||||
370→Task ID: 6-b
|
||||
371→Agent: Users Enhancement Agent
|
||||
372→Task: Users tabs, user notes, region column
|
||||
373→
|
||||
374→Stage Summary:
|
||||
375→- Schema change, 2 APIs modified, 2 pages enhanced
|
||||
376→- ESLint: 0 errors
|
||||
377→
|
||||
378→---
|
||||
379→Task ID: 6-c
|
||||
380→Agent: Enhancement Agent
|
||||
381→Task: Wallet chart, settings backup/restore
|
||||
382→
|
||||
383→Stage Summary:
|
||||
384→- 2 new APIs, 2 pages modified
|
||||
385→- ESLint: 0 errors
|
||||
386→
|
||||
387→---
|
||||
388→Task ID: 7-a
|
||||
389→Agent: Footer + CSS Polish Agent
|
||||
390→Task: Footer, dark-mode fixes, CSS enhancements
|
||||
391→
|
||||
392→Stage Summary:
|
||||
393→- 1 new component, 4 files modified
|
||||
394→- ESLint: 0 errors
|
||||
395→
|
||||
396→---
|
||||
397→Task ID: 7-b
|
||||
398→Agent: Keyboard Shortcuts Agent
|
||||
399→Task: Keyboard shortcuts + sidebar hints
|
||||
400→
|
||||
401→Stage Summary:
|
||||
402→- 1 new hook, 2 files modified
|
||||
403→- ESLint: 0 errors
|
||||
404→
|
||||
405→---
|
||||
406→Task ID: 7-c
|
||||
407→Agent: Dashboard Sparklines + Seed/Locales Agent
|
||||
408→Task: Sparklines, seed visual overhaul, locales search
|
||||
409→
|
||||
410→Stage Summary:
|
||||
411→- 3 files modified
|
||||
412→- ESLint: 0 errors
|
||||
413→
|
||||
414→---
|
||||
415→Task ID: 7-d
|
||||
416→Agent: Settings Overhaul Agent
|
||||
417→Task: Settings visual overhaul with descriptions
|
||||
418→
|
||||
419→Stage Summary:
|
||||
420→- 2 files modified
|
||||
421→- ESLint: 0 errors
|
||||
422→
|
||||
423→---
|
||||
424→Task ID: 8
|
||||
425→Agent: Main Coordinator + 3 subagents
|
||||
426→Task: Branded loading, purchase detail modal, catalog enhancements, global search, transactions tab, audit copy, categories view, dashboard analytics, 404 page, empty state gradients
|
||||
427→
|
||||
428→
|
||||
429→Work Log:
|
||||
430→- Task 8-a: Branded loading screen with TS logo, progress bar, gradient orbs
|
||||
431→- Task 8-a: Purchase detail modal in user detail page with copy TX hash
|
||||
432→- Task 8-a: Catalog tree color accents by product count, stock indicators, summary bar
|
||||
433→- Task 8-a: Global user search in command palette (debounced, 2+ chars)
|
||||
434→- Task 8-b: New transactions/bulk API route
|
||||
435→- Task 8-b: 4th tab in wallets page with full transaction history
|
||||
436→- Task 8-b: Copy All + per-row Copy JSON buttons on audit page
|
||||
437→- Task 8-b: Categories quick view dialog showing products
|
||||
438→- Task 8-c: Dashboard 30-day revenue trend AreaChart
|
||||
439→- Task 8-c: Dashboard user funnel horizontal BarChart
|
||||
440→- Task 8-c: Enhanced 404 page with search icon and Go to Dashboard button
|
||||
441→- Task 8-c: Sidebar logo hover scale-110 micro-interaction
|
||||
442→- Task 8-c: empty-state radial gradient CSS class applied to 8 empty states
|
||||
443→
|
||||
444→
|
||||
445→Stage Summary:
|
||||
446→- 1 new API route (transactions/bulk), 1 products/bulk updated
|
||||
447→- 10 page components modified
|
||||
448→- 2 shared components modified (command-palette, admin-sidebar)
|
||||
449→- 1 global CSS enhancement (loading keyframe, empty-state class)
|
||||
450→- ESLint: 0 errors, 0 warnings
|
||||
451→
|
||||
452→---
|
||||
453→Task ID: 9-a
|
||||
454→Agent: Frontend Styling Expert
|
||||
455→Task: Comprehensive CSS and layout styling improvements
|
||||
456→
|
||||
457→Work Log:
|
||||
458→- **globals.css**: Added ~265 lines of new CSS utilities and animations
|
||||
459→ - Animated gradient border effect on focused inputs (gradientBorder keyframes with rotating oklch colors)
|
||||
460→ - `.glass-card` utility class for glassmorphism (backdrop-blur, semi-transparent bg, dark mode variant)
|
||||
461→ - `.page-section-enter` staggered section reveal animation (6 children, 60ms delay increments)
|
||||
462→ - `.stat-value` class with tabular-nums, font-variant-numeric, letter-spacing
|
||||
463→ - `.glow-success`, `.glow-warning`, `.glow-danger` subtle glow effects (different radii for light/dark)
|
||||
464→ - Improved `::selection` styling with warm orange accent and dark mode variant
|
||||
465→ - `.bg-noise` SVG noise texture overlay class with light/dark opacity variants
|
||||
466→ - `.ring-accent` focus ring variant
|
||||
467→ - `.kpi-shimmer` hover shimmer animation for cards (diagonal gradient sweep)
|
||||
468→ - `.count-up` number entry animation
|
||||
469→ - `.colon-pulse` clock colon separator animation
|
||||
470→ - `.gradient-border-b` / `.gradient-border-t` fade-in gradient borders for header/footer
|
||||
471→ - `.alternate-rows` table even-row background and first-column left border
|
||||
472→ - `.table-header-gradient` subtle gradient on thead
|
||||
473→ - `.sidebar-indicator-dot` pulsing dot animation
|
||||
474→ - Improved tbody tr hover with box-shadow inset accent
|
||||
475→- **admin-sidebar.tsx**: 5 styling improvements
|
||||
476→ - Active nav item left-border accent (2px, sidebar-primary color) via data-active
|
||||
477→ - Icon color transition on hover (muted → primary) on all nav items
|
||||
478→ - Animated pulsing indicator dot on Purchases item when pending count > 0
|
||||
479→ - Polished footer: ring on avatar, improved spacing (px-3 py-2), mt-0.5 on badge
|
||||
480→ - Connection indicator: smaller dot (1.5), glow-success class, improved opacity
|
||||
481→- **admin-header.tsx**: 3 improvements
|
||||
482→ - Gradient bottom border (transparent → border → transparent) via gradient-border-b class
|
||||
483→ - Backdrop-blur-md with bg-background/80 for translucent header
|
||||
484→ - Pulsing colon separator in RealtimeClock component (colon-pulse animation)
|
||||
485→- **admin-footer.tsx**: 4 improvements
|
||||
486→ - Gradient top border matching header via gradient-border-t
|
||||
487→ - Hover color transitions on text elements
|
||||
488→ - Improved spacing (py-3, gap-2) and text sizing (11px for tech stack)
|
||||
489→ - Semi-transparent text variants for visual hierarchy
|
||||
490→- **dashboard-page.tsx**: 4 improvements
|
||||
491→ - KPI cards: added kpi-shimmer hover effect, stat-value + count-up classes
|
||||
492→ - ChartCard: added optional icon prop with accent color, renders icon next to title
|
||||
493→ - All 8 ChartCard usages now pass appropriate icons (TrendingUp, Users, Package, etc.)
|
||||
494→ - Recent purchases table: alternate-rows + table-header-gradient classes
|
||||
495→- **users-page.tsx**: Table improvements
|
||||
496→ - Added alternate-rows + table-header-gradient classes to Table
|
||||
497→ - First column (ID) gets subtle left border accent (border-l-2 border-l-primary/10)
|
||||
498→- **purchases-page.tsx**: Table improvements
|
||||
499→ - Added alternate-rows + table-header-gradient classes to Table
|
||||
500→ - First column (ID) gets subtle left border accent (border-l-2 border-l-primary/10)
|
||||
501→
|
||||
502→Stage Summary:
|
||||
503→- 7 files modified (globals.css, admin-sidebar, admin-header, admin-footer, dashboard-page, users-page, purchases-page)
|
||||
504→- ~265 lines of new CSS, ~50 lines of TSX changes
|
||||
505→- ESLint: 0 errors, 0 warnings
|
||||
506→
|
||||
507→---
|
||||
508→Task ID: 9-b
|
||||
509→Agent: Feature Implementation Agent
|
||||
510→Task: 6 feature additions — batch actions, activity feed, product clone, timeline, wallet summary
|
||||
511→
|
||||
512→Work Log:
|
||||
513→- **1. Users Batch Actions** (users-page.tsx + API route)
|
||||
514→ - Added Checkbox import from shadcn/ui, ShieldBan/ShieldCheck icons from lucide-react, toast from sonner
|
||||
515→ - Added `selectedIds` (Set<number>) and `batchLoading` state
|
||||
516→ - Added `toggleSelect()`, `toggleSelectAll()`, `handleBatchStatus()` functions
|
||||
517→ - Added checkbox column (first column) with "Select All" in header
|
||||
518→ - Added floating action bar at bottom: selected count, Ban/Unban buttons, Clear button
|
||||
519→ - Floating bar uses `animate-in slide-in-from-bottom-4 fade-in` with backdrop-blur
|
||||
520→ - Created `src/app/api/users/batch-status/route.ts` — POST with {userIds, newStatus}, uses updateMany
|
||||
521→
|
||||
522→- **2. Purchases Batch Actions** (purchases-page.tsx + API route)
|
||||
523→ - Added Checkbox import, CheckCircle2/XCircle2 icons
|
||||
524→ - Added `selectedIds`, `batchLoading` state and toggle/batch functions
|
||||
525→ - Added checkbox column with "Select All" in header
|
||||
526→ - Added floating action bar: selected count, Approve/Cancel buttons, Clear button
|
||||
527→ - Created `src/app/api/purchases/batch-status/route.ts` — POST with {purchaseIds, status}, only updates pending
|
||||
528→
|
||||
529→- **3. Dashboard Activity Feed Improvements** (activity-feed.tsx + dashboard API)
|
||||
530→ - Modified `src/app/api/stats/dashboard/route.ts` to return `recentActivity` (last 8 audit logs)
|
||||
531→ - Changed from fetching `/api/audit/bulk` to using dashboard's `recentActivity` field
|
||||
532→ - Added per-action icon mapping with 15 action types (login, balance_adjust, user_banned, etc.)
|
||||
533→ - Added color-coded action badges with outline variant (bg-*/15 text-*/400 border-*/25)
|
||||
534→ - Improved relative time: "X seconds/minutes/hours/days/months ago" with proper pluralization
|
||||
535→ - Added staggered enter animation (50ms per item, fade-in + slide-in-from-left-1)
|
||||
536→ - Increased max height from h-48 to h-64 for more items visible
|
||||
537→
|
||||
538→- **4. Product Clone Feature** (catalog-page.tsx + API route)
|
||||
539→ - Added Copy icon import from lucide-react
|
||||
540→ - Added `handleCloneProduct()` function that POSTs to clone API
|
||||
541→ - Added Duplicate button (Copy icon, orange color) between Edit and Delete buttons on each product row
|
||||
542→ - Created `src/app/api/products/[id]/clone/route.ts` — POST, copies all fields, appends " (Copy)" to name
|
||||
543→ - Success toast: "Product cloned as \"{name} (Copy)\""
|
||||
544→
|
||||
545→- **5. User Detail Activity Timeline** (user-detail-page.tsx)
|
||||
546→ - Replaced table layout with vertical timeline (absolute left border line, colored dots)
|
||||
547→ - Added `actionDotColor()` helper — maps action types to Tailwind bg-* colors
|
||||
548→ - Added `relativeTime()` helper for compact time display ("3m ago", "2h ago")
|
||||
549→ - Added `expandedTimelineId` state for expandable details
|
||||
550→ - Each entry: colored dot (ring-4 ring-background), ActionBadge, relative time, chevron toggle
|
||||
551→ - Clicking expands: shows details in `<pre>` block with full date, with animation
|
||||
552→ - Added `ChevronDown`/`ChevronRight` icons for expand/collapse indicators
|
||||
553→ - Staggered entry animation (30ms per item)
|
||||
554→
|
||||
555→- **6. Wallets Balance Summary Cards** (wallets-page.tsx + overview API)
|
||||
556→ - Modified `src/app/api/wallets/overview/route.ts` to include `activeWallets` count
|
||||
557→ - Added `activeWallets` to OverviewData interface
|
||||
558→ - Added 3 glass-card mini cards at top of Owner Summary tab:
|
||||
559→ - Total Balance (DollarSign icon, orange, stat-value formatting)
|
||||
560→ - Total Wallets (Wallet icon, violet)
|
||||
561→ - Active Wallets (Wallet icon, emerald, with percentage of total)
|
||||
562→ - Uses existing `.glass-card` + `.stat-value` CSS classes
|
||||
563→
|
||||
564→Stage Summary:
|
||||
565→- 3 new API routes created (users/batch-status, purchases/batch-status, products/[id]/clone)
|
||||
566→- 1 API route modified (wallets/overview)
|
||||
567→- 6 page components modified (users-page, purchases-page, activity-feed, catalog-page, user-detail-page, wallets-page)
|
||||
568→- 1 dashboard API modified (stats/dashboard)
|
||||
569→- ESLint: 0 errors, 0 warnings
|
||||
570→
|
||||
571→---
|
||||
572→Task ID: 9-c
|
||||
573→Agent: Main Coordinator
|
||||
574→Task: QA Round 6 — Code review, bug fixes, styling, features
|
||||
575→
|
||||
576→Work Log:
|
||||
577→- Performed comprehensive code review QA via Explore subagent — found 24 bugs (2 critical, 5 high, 9 medium, 8 low)
|
||||
578→- Fixed 9 bugs directly (Settings PUT no-op, audit userId filter, product DELETE safety, CSV export, rate limiter leak, catalog res.ok, quick actions role, command palette nav, "use server" in API route)
|
||||
579→- Launched frontend-styling-expert subagent for comprehensive CSS/layout styling (~265 lines new CSS, 7 files modified)
|
||||
580→- Launched full-stack-developer subagent for 6 new features (batch actions×2, activity feed, product clone, timeline, wallet summary)
|
||||
581→- Fixed runtime compilation error (XCircle2 not in lucide-react → replaced with Ban)
|
||||
582→- Verified: ESLint 0 errors, GET / 200 (8.0s compile)
|
||||
583→
|
||||
584→Stage Summary:
|
||||
585→- 9 bug fixes across 8 files
|
||||
586→- 6 new features (3 new API routes, 7 modified components)
|
||||
587→- Comprehensive styling overhaul (7 files, ~265 lines CSS)
|
||||
588→- Total: 128+ source files, 40 API routes
|
||||
589→- ESLint: 0 errors, 0 warnings
|
||||
590→- Compile: GET / 200 verified
|
||||
591→
|
||||
592→---
|
||||
593→Task ID: 10-a
|
||||
594→Agent: API Routes Agent
|
||||
595→Task: Chatbot settings, leads, chat, operator API routes
|
||||
596→
|
||||
597→Work Log:
|
||||
598→- Created `src/lib/chatbot-config.ts` — shared 5-minute cache module for chatbot settings (reads from SiteSetting, used by admin/chatbot and chat routes)
|
||||
599→- Created `src/app/api/admin/chatbot/route.ts` — GET returns all 12 chatbot settings with defaults, masks API key (sk-xx****xxxx pattern); PUT validates temperature (0-2), max_tokens (50-4000), max_history (1-50), provider (openai|deepseek|openrouter|ollama|custom), upserts in transaction, skips masked values, clears cache
|
||||
600→- Created `src/app/api/leads/bulk/route.ts` — GET with pagination (page/limit), search across name/phone/email/telegram/telegramId, status filter, _count chatSessions, default sort by createdAt desc
|
||||
601→- Created `src/app/api/leads/[id]/route.ts` — GET returns lead with chatSessions (id, sessionId, isActive, createdAt, customerProfile); PUT updates status/notes/customFields with validation, writes audit log
|
||||
602→- Created `src/app/api/leads/[id]/sessions/route.ts` — GET returns all chat sessions for a lead with parsed messages JSON array
|
||||
603→- Created `src/app/api/chat/route.ts` — POST for TG bot integration: finds/creates ChatSession, loads chatbot config via cached getChatbotConfig, builds system prompt (system_prompt + knowledge_base + customer profile + catalog context from products DB), handles sleep mode, calls LLM via z-ai-web-dev-sdk `llm_chat` function, saves user+assistant messages, extracts lead data via regex (name/phone/email/telegram), generates customer profile (intent/interests/sentiment/readiness/summary), auto-creates/updates Lead record, returns reply with sessionId/leadId/profile. Graceful fallback if SDK fails.
|
||||
604→- Created `src/app/api/operator/route.ts` — POST connect (autoReplyDisabled=true, operatorName, operatorConnectedAt) / disconnect (clear), with audit log
|
||||
605→
|
||||
606→Stage Summary:
|
||||
607→- 6 new API routes + 1 shared lib (chatbot-config.ts)
|
||||
608→- Total: 879 lines across 7 files
|
||||
609→- ESLint: 0 errors, 0 warnings on new files
|
||||
610→- All routes use getAuth from @/lib/auth-middleware
|
||||
611→- Named exports (GET/POST/PUT), try/catch error handling
|
||||
612→- z-ai-web-dev-sdk used only in chat route
|
||||
613→
|
||||
614→---
|
||||
615→Task ID: 10-b
|
||||
616→Agent: Frontend Agent
|
||||
617→Task: Chatbot settings page, leads management page, matrix rain, sidebar nav, routing
|
||||
618→
|
||||
619→Work Log:
|
||||
620→- **globals.css**: Added ~33 lines of Matrix Rain CSS (`.matrix-rain` with `::before`/`::after` pseudo-elements, `matrixFall`/`matrixFall2` keyframes, dark mode variant with increased opacity)
|
||||
621→- **login/page.tsx**: Added `<div className="matrix-rain" />` after opening container div, before gradient mesh background
|
||||
622→- **chatbot-settings-page.tsx**: Created comprehensive 4-tab chatbot settings page (NEW FILE, ~280 lines)
|
||||
623→ - Tab 1 "Общие": Bot enabled switch, sleep mode switch with description, sleep message textarea, system prompt textarea (6 rows), welcome message textarea (3 rows)
|
||||
624→ - Tab 2 "Параметры ИИ": Temperature slider (0-2, step 0.1) with live value badge, Max Tokens number input (50-4000), Max History number input (1-50) with description
|
||||
625→ - Tab 3 "База знаний": Large textarea (12 rows) for knowledge base with placeholder showing markdown-style format, description card
|
||||
626→ - Tab 4 "Провайдер": Provider select (openai/deepseek/openrouter/ollama/custom), API endpoint input, API key password input with security note
|
||||
627→ - Save button at bottom of each card section, loading skeleton on mount, toast on success/error
|
||||
628→ - All text in Russian, glass-card styling, page-enter animation, proper dark theme
|
||||
629→- **leads-page.tsx**: Created full leads management page with split view (NEW FILE, ~580 lines)
|
||||
630→ - Left panel: search input with Search icon, 6 status filter buttons (Все/Новые/Контакты/Квалифиц./Потерянные/Спам), data table with 8 columns (Имя with avatar, Telegram, Телефон, Email, Статус badge, AI Скор %, Сессий count, Дата)
|
||||
631→ - Status badges: opacity-based colors per status (blue/amber/emerald/red/zinc)
|
||||
632→ - AI Score color coding: ≥70% emerald, ≥40% amber, <40% red
|
||||
633→ - Right panel (Sheet): lead info header with avatar/name/status badge/operator badge, created date
|
||||
634→ - Contact info card (TG/Phone/Email), AI Profile card (intent/interests/sentiment/readiness with color-coded badges, summary)
|
||||
635→ - Notes textarea with save button, status quick-change buttons, operator actions ("Взять чат" / "Передать боту")
|
||||
636→ - Chat sessions: expandable list, each session shows messages as chat bubbles (user left-aligned bg-muted, bot right-aligned bg-primary/10), rounded corners, timestamps
|
||||
637→ - API integration: GET /api/leads/bulk with pagination/search/status, GET /api/leads/{id}, GET /api/leads/{id}/sessions, PUT /api/leads/{id}, POST /api/operator
|
||||
638→ - Uses shared Pagination component, glass-card styling, empty state, loading skeletons
|
||||
639→- **admin-sidebar.tsx**: Added 2 new nav items to manageNav: "AI Chatbot" (Bot icon, /chatbot) and "Leads" (Target icon, /leads)
|
||||
640→- **page.tsx**: Added imports for ChatbotSettingsPage and LeadsPage, added route cases for #/chatbot and #/leads
|
||||
641→
|
||||
642→Stage Summary:
|
||||
643→- 2 new page components (chatbot-settings-page.tsx, leads-page.tsx)
|
||||
644→- 4 files modified (globals.css, login/page.tsx, admin-sidebar.tsx, page.tsx)
|
||||
645→- ESLint: 0 errors, 0 warnings on new/modified files (only pre-existing keepalive.js errors)
|
||||
646→- Dev log: GET / 200 in 62ms — compiles successfully
|
||||
647→- All text in Russian, dark theme compatible, named exports, 'use client' directive
|
||||
647
tool-results/read_1786098856442_ced0ccbfd651.txt
Normal file
647
tool-results/read_1786098856442_ced0ccbfd651.txt
Normal file
@@ -0,0 +1,647 @@
|
||||
1→ 1→# Telegram Shop Admin Panel — Worklog
|
||||
2→ 2→
|
||||
3→ 3→---
|
||||
4→ 4→## Current Project Status (2026-08-06 — AI Chatbot + Leads + Sleep Mode + Matrix BG Sprint)
|
||||
5→ 5→
|
||||
6→ 6→### Assessment
|
||||
7→ 7→
|
||||
8→ 8→**Code Quality:**
|
||||
9→ 9→- ✅ ESLint: 0 errors, 0 warnings
|
||||
10→ 10→- ✅ All 13 original pages preserved and working
|
||||
11→ 11→- ✅ 2 new pages added (AI Chatbot Settings, Leads)
|
||||
12→ 12→- ✅ 8 new API routes (chatbot, leads, chat, operator)
|
||||
13→ 13→- ✅ 3 new Prisma models (ChatSession, Lead, SiteSetting)
|
||||
14→ 14→- ✅ Matrix Rain CSS background on login page
|
||||
15→ 15→- ✅ Dark theme compatible, Russian UI
|
||||
16→ 16→
|
||||
17→ 17→**Files:** 140+ source files
|
||||
18→ 18→- 15 page components (added AI Chatbot, Leads)
|
||||
19→ 19→- 48+ API route handlers
|
||||
20→ 20→- 15 shared/layout components
|
||||
21→ 21→- 15 Prisma models
|
||||
22→ 22→
|
||||
23→ 23→**New Features This Round:**
|
||||
24→ 24→1. **AI Chatbot Settings** (`#/chatbot`) — 4-tab configuration page
|
||||
25→ 25→ - General: enabled toggle, sleep mode toggle + message, system prompt, welcome message
|
||||
26→ 26→ - AI Parameters: temperature slider, max tokens, max history per client
|
||||
27→ 27→ - Knowledge Base: dictionary/lexicon textarea for product info & FAQ
|
||||
28→ 28→ - Provider: OpenAI/DeepSeek/OpenRouter/Ollama/Custom, API endpoint & key
|
||||
29→ 29→2. **Leads Management** (`#/leads`) — full leads & conversations page
|
||||
30→ 30→ - Table with search, status filters (new/contacted/qualified/lost/spam)
|
||||
31→ 31→ - AI profile card (intent, interests, sentiment, readiness, budget)
|
||||
32→ 32→ - Chat session viewer with message bubbles
|
||||
33→ 33→ - Operator takeover (connect/disconnect) with audit log
|
||||
34→ 34→ - Notes editing, quick status change
|
||||
35→ 35→3. **Sleep Mode** — when enabled, /start shows AI chat instead of catalog
|
||||
36→ 36→ - Bot informs user shop is restocking
|
||||
37→ 37→ - Collects contacts for future notification
|
||||
38→ 38→4. **Chat API** (`POST /api/chat`) — TG bot integration
|
||||
39→ 39→ - Session management, LLM via z-ai-web-dev-sdk
|
||||
40→ 40→ - Automatic lead extraction (name, phone, email, telegram)
|
||||
41→ 41→ - Customer profile generation (intent, interests, sentiment, readiness)
|
||||
42→ 42→ - Catalog context injection into prompts
|
||||
43→ 43→ - Individual conversation history per client (configurable depth)
|
||||
44→ 44→5. **Matrix Rain Background** — CSS-only animation on login page
|
||||
45→ 45→ - Two layers of falling characters at very low opacity (0.025-0.06)
|
||||
46→ 46→ - Dark mode adaptive (brighter in dark theme)
|
||||
47→ 47→6. **Documentation** — comprehensive docs/admin-nextjs-guide.md rewrite
|
||||
48→ 48→ - All 48+ API routes documented
|
||||
49→ 49→ - Full data model description
|
||||
50→ 50→ - AI bot architecture, profiling, operator flow documented
|
||||
51→ 51→
|
||||
52→ 52→**New API Routes:**
|
||||
53→ 53→- `GET/PUT /api/admin/chatbot` — chatbot settings CRUD
|
||||
54→ 54→- `POST /api/chat` — chat endpoint for TG bot
|
||||
55→ 55→- `GET /api/leads/bulk` — paginated leads list
|
||||
56→ 56→- `GET/PUT /api/leads/[id]` — lead detail/update
|
||||
57→ 57→- `GET /api/leads/[id]/sessions` — chat sessions for a lead
|
||||
58→ 58→- `POST /api/operator` — operator connect/disconnect
|
||||
59→ 59→
|
||||
60→ 60→**New DB Models:**
|
||||
61→ 61→- `ChatSession` — chat sessions with messages JSON, customer profile, operator state
|
||||
62→ 62→- `Lead` — extracted leads with AI score, status, custom fields
|
||||
63→ 63→- `SiteSetting` — key-value settings storage for chatbot config
|
||||
64→ 64→
|
||||
65→ 65→### Unresolved Issues / Risks
|
||||
66→ 66→1. **Sandbox OOM** — Dev server needs ~1.5GB, standalone ~50MB. Use production build.
|
||||
67→ 67→2. **Settings import** — Endpoint returns 'not yet implemented'
|
||||
68→ 68→3. **Photo uploads** — No multipart API yet
|
||||
69→ 69→4. **SSE live updates** — Dashboard refreshes but no push
|
||||
70→ 70→5. **Client-side sort** — Sort indicator shown but only sorts current page
|
||||
71→ 71→6. **Dashboard sparklines** — Use random data, no real history
|
||||
72→ 72→7. **Multi-admin identity** — Audit log stores role string, not admin ID
|
||||
73→ 73→
|
||||
74→ 74→### Priority Recommendations for Next Phase
|
||||
75→ 75→1. **HIGH**: Dockerfile + docker-compose.yml for ARM deployment
|
||||
76→ 76→2. **HIGH**: Test on real ARM device
|
||||
77→ 77→3. **HIGH**: Connect to Gitea, push changes
|
||||
78→ 78→4. **MEDIUM**: Implement settings import logic
|
||||
79→ 79→5. **MEDIUM**: Product photo upload API
|
||||
80→ 80→6. **MEDIUM**: SSE endpoint for real-time dashboard
|
||||
81→ 81→7. **MEDIUM**: Server-side sort for all list APIs
|
||||
82→ 82→8. **LOW**: Real KPI history for sparklines
|
||||
83→ 83→9. **LOW**: Multi-admin users table
|
||||
84→ 84→
|
||||
85→ 85→
|
||||
86→ 86→---
|
||||
87→ 87→Task ID: 10
|
||||
88→ 88→Agent: Main Coordinator + 3 subagents
|
||||
89→ 89→Task: AI Chatbot, Leads, Sleep Mode, Matrix Background, Documentation
|
||||
90→ 90→
|
||||
91→ 91→Work Log:
|
||||
92→ 92→- Studied qrgeo project (chat, leads, chatbot admin, schema, AdminLeadsView)
|
||||
93→ 93→- Added 3 Prisma models: ChatSession, Lead, SiteSetting
|
||||
94→ 94→- Created 8 API routes (chatbot config, chat, leads, operator)
|
||||
95→ 95→- Created chatbot settings page (4 tabs: General, AI Params, Knowledge Base, Provider)
|
||||
96→ 96→- Created leads management page (table, chat viewer, operator takeover, AI profiles)
|
||||
97→ 97→- Added Matrix Rain CSS background to login page
|
||||
98→ 98→- Updated sidebar navigation with AI Chatbot and Leads items
|
||||
99→ 99→- Updated page.tsx routing for new pages
|
||||
100→ 100→- Rewrote docs/admin-nextjs-guide.md (15 models, 48+ API routes, full architecture)
|
||||
101→ 101→- Updated worklog.md
|
||||
102→ 102→
|
||||
103→ 103→Stage Summary:
|
||||
104→ 104→- 8 new API routes, 2 new page components, 3 new DB models
|
||||
105→ 105→- 1 shared library (chatbot-config.ts)
|
||||
106→ 106→- ESLint: 0 errors, 0 warnings
|
||||
107→ 107→- Total: 140+ source files, 48+ API routes, 15 Prisma models
|
||||
108→ 108→
|
||||
109→ 109→
|
||||
110→ 110→### Assessment
|
||||
111→ 111→
|
||||
112→ 112→**Code Quality:**
|
||||
113→ 113→- ✅ ESLint: 0 errors, 0 warnings
|
||||
114→ 114→- ✅ Server compiles successfully (GET / 200, 8.0s compile)
|
||||
115→ 115→- ✅ All navigation uses `window.location.hash`
|
||||
116→ 116→- ✅ All 13 page components use named exports, `@/` imports, `sonner` toasts
|
||||
117→ 117→- ✅ Dark-theme-compatible badge colors (opacity-based)
|
||||
118→ 118→- ✅ ErrorBoundary wrapping all page renders
|
||||
119→ 119→- ✅ Auth: secure cookie flag in production, no hardcoded secrets
|
||||
120→ 120→- ✅ Sticky footer, keyboard shortcuts (1-9), focus-visible ring, sticky table headers
|
||||
121→ 121→- ✅ Branded loading screen with progress bar animation
|
||||
122→ 122→
|
||||
123→ 123→**Files:** 128+ source files
|
||||
124→ 124→- 13 page components (dashboard, catalog, users×2, wallets, purchases, audit, categories, locations, settings, locales, seed)
|
||||
125→ 125→- 40 API route handlers (3 new: batch-status×2, product clone)
|
||||
126→ 126→- 15 shared/layout components + 3 shared utility components
|
||||
127→ 127→- 3 hooks (use-debounce, use-mobile, use-keyboard-shortcuts)
|
||||
128→ 128→- 1 store (auth-store), 1 Prisma schema (12 models)
|
||||
129→ 129→- 48 shadcn/ui components
|
||||
130→ 130→
|
||||
131→ 131→**Bug Fixes This Round (9 bugs fixed):**
|
||||
132→ 132→1. **[CRITICAL] Settings PUT no-op** → Now actually persists to in-memory SETTINGS object with key validation
|
||||
133→ 133→2. **[HIGH] Audit userId filter false matches** → Added trailing comma in JSON substring match (`"userId":${id},`) prevents ID=1 matching ID=10
|
||||
134→ 134→3. **[HIGH] Product DELETE no safety check** → Now checks `purchaseCount` before deleting, returns 400 with descriptive error
|
||||
135→ 135→4. **[HIGH] CSV export injection** → Added proper `escapeCsv()` function that doubles internal quotes and wraps all fields
|
||||
136→ 136→5. **[HIGH] Rate limiter memory leak** → Added `setInterval` cleanup every 10 minutes for expired entries
|
||||
137→ 137→6. **[HIGH] openProductModal missing res.ok** → Now checks `treeRes.ok` and `locRes.ok` before parsing JSON
|
||||
138→ 138→7. **[MEDIUM] Quick Actions seed visible to all** → Now gated by `role === 'super_admin'`
|
||||
139→ 139→8. **[MEDIUM] Command palette duplicate nav** → "Clear Data" now navigates to `#/seed?action=clear`
|
||||
140→ 140→9. **[LOW] "use server" in API route** → Removed from purchases/[id]/route.ts
|
||||
141→ 141→
|
||||
142→ 142→**New Features This Round:**
|
||||
143→ 143→1. **Users batch actions** — Checkbox column, Select All, floating action bar with Ban/Unban, batch API route
|
||||
144→ 144→2. **Purchases batch actions** — Checkbox column, Select All, floating action bar with Approve/Cancel, batch API route
|
||||
145→ 145→3. **Dashboard activity feed overhaul** — Uses recentActivity from dashboard API, 15 action-type icons, color-coded badges, relative time, staggered animations
|
||||
146→ 146→4. **Product clone** — Duplicate button (Copy icon) on each product row, creates copy with "(Copy)" suffix
|
||||
147→ 147→5. **User detail activity timeline** — Vertical timeline with colored dots, expandable details, relative time, staggered entry
|
||||
148→ 148→6. **Wallets balance summary** — 3 glass-card mini cards (Total Balance, Total Wallets, Active Wallets %) in Owner Summary tab
|
||||
149→ 149→
|
||||
150→ 150→**Styling Improvements This Round:**
|
||||
151→ 151→1. **~265 lines of new CSS** — glass-card, kpi-shimmer, count-up, colon-pulse, gradient borders, alternate-rows, table-header-gradient, glow effects, noise texture, page-section-enter
|
||||
152→ 152→2. **Sidebar polish** — Active nav 2px left-border accent, icon hover transitions, pulsing dot on Purchases, polished footer
|
||||
153→ 153→3. **Header polish** — Gradient bottom border, backdrop-blur translucent header, pulsing colon in clock
|
||||
154→ 154→4. **Footer polish** — Gradient top border, hover transitions, improved spacing and text hierarchy
|
||||
155→ 155→5. **Dashboard KPIs** — Shimmer hover effect, stat-value formatting, chart card icons
|
||||
156→ 156→6. **Table improvements** — Alternating row colors, first-column left accent, gradient headers on users/purchases
|
||||
157→ 157→
|
||||
158→ 158→**Completed Modifications & Verification:**
|
||||
159→ 159→- ✅ ESLint: 0 errors, 0 warnings after all changes
|
||||
160→ 160→- ✅ Compile: GET / 200 (8.0s compile, 321ms render)
|
||||
161→ 161→- ✅ 128+ source files, 40 API routes
|
||||
162→ 162→- ✅ All features from Rounds 1-5 preserved and working
|
||||
163→ 163→
|
||||
164→ 164→### Unresolved Issues / Risks
|
||||
165→ 165→1. **Sandbox OOM** — Dev server dies after compilation. Not a code bug. Production build recommended.
|
||||
166→ 166→2. **Photo uploads** — Product photo upload not implemented (no multipart API)
|
||||
167→ 167→3. **Real backend integration** — Standalone Prisma/SQLite, needs shared DB volume for Docker
|
||||
168→ 168→4. **SSE live updates** — Dashboard auto-refreshes but no push updates
|
||||
169→ 169→5. **Categories/Locations pagination** — Still fetches all data (client-side filter)
|
||||
170→ 170→6. **Settings import** — Endpoint returns 'not yet implemented'
|
||||
171→ 171→7. **No individual admin identity** — Audit log stores role string, not admin ID
|
||||
172→ 172→8. **Dashboard sparklines use random data** — No real historical data yet
|
||||
173→ 173→9. **Transactions API** — No date range or type filtering
|
||||
174→ 174→10. **Client-side sort conflicts with server-side pagination** — Sort indicator shown but only sorts current page
|
||||
175→ 175→
|
||||
176→ 176→### Priority Recommendations for Next Phase
|
||||
177→ 177→1. **HIGH**: Add production Dockerfile and docker-compose.yml
|
||||
178→ 178→2. **HIGH**: Test on real ARM device, fix any runtime errors
|
||||
179→ 179→3. **HIGH**: Connect to Gitea and push all changes
|
||||
180→ 180→4. **MEDIUM**: Implement actual settings import logic
|
||||
181→ 181→5. **MEDIUM**: Add photo upload API for products
|
||||
182→ 182→6. **MEDIUM**: Add SSE endpoint for real-time dashboard updates
|
||||
183→ 183→7. **MEDIUM**: Add server-side pagination to categories, locations APIs
|
||||
184→ 184→8. **MEDIUM**: Add date/filter params to transactions API
|
||||
185→ 185→9. **MEDIUM**: Fix client-side sort to use server-side sorting params
|
||||
186→ 186→10. **LOW**: Store historical KPI data for real sparklines
|
||||
187→ 187→11. **LOW**: Add admin users table for multi-admin identity
|
||||
188→ 188→
|
||||
189→ 189→
|
||||
190→ 190→---
|
||||
191→ 191→Task ID: 1-12 (initial build)
|
||||
192→ 192→Agent: Main Coordinator + 4 subagents
|
||||
193→ 193→Task: Full admin panel build from scratch
|
||||
194→ 194→
|
||||
195→ 195→Summary:
|
||||
196→ 196→- Prisma schema (11 tables), auth system (HMAC), app shell (sidebar/header)
|
||||
197→ 197→- 11 page components with 30+ API routes
|
||||
198→ 198→- Seed data identical to original project
|
||||
199→ 199→- Real i18n locale data (en/es/de)
|
||||
200→ 200→- Pushed to Gitea PR #132
|
||||
201→ 201→
|
||||
202→ 202→---
|
||||
203→ 203→Task ID: 5-a
|
||||
204→ 204→Agent: Styling Agent
|
||||
205→ 205→Task: Global CSS and login page styling overhaul
|
||||
206→ 206→
|
||||
207→ 207→Work Log:
|
||||
208→ 208→- Added custom scrollbar styling (thin, rounded, themed)
|
||||
209→ 209→- Added smooth transition classes for interactive elements
|
||||
210→ 210→- Added page-enter fade-in animation
|
||||
211→ 211→- Added card-hover lift effect
|
||||
212→ 212→- Added skeleton shimmer animation
|
||||
213→ 213→- Added subtle gradient mesh background to login
|
||||
214→ 214→- Added glass-morphism card effect to login
|
||||
215→ 215→- Added animated loading spinner to login button
|
||||
216→ 216→- Added keyboard shortcut hint
|
||||
217→ 217→
|
||||
218→ 218→Stage Summary:
|
||||
219→ 219→- globals.css: Added ~80 lines of custom CSS (scrollbars, animations, hover effects)
|
||||
220→ 220→- login/page.tsx: Complete visual redesign with gradient background, glass card, better typography
|
||||
221→ 221→- Both files pass ESLint
|
||||
222→ 222→
|
||||
223→ 223→---
|
||||
224→ 224→Task ID: 5-b
|
||||
225→ 225→Agent: Dashboard Agent
|
||||
226→ 226→Task: Dashboard styling and features overhaul
|
||||
227→ 227→
|
||||
228→ 228→Work Log:
|
||||
229→ 229→- Added refresh button with spin animation
|
||||
230→ 230→- Added auto-refresh toggle (30s interval)
|
||||
231→ 231→- Added last updated timestamp
|
||||
232→ 232→- Improved KPI cards with card-hover, left border accent, tabular-nums
|
||||
233→ 233→- Improved chart cards with card-hover, h-72
|
||||
234→ 234→- Added wallet count bar chart
|
||||
235→ 235→- Wrapped activity feed in proper Card
|
||||
236→ 236→
|
||||
237→ 237→Stage Summary:
|
||||
238→ 238→- dashboard-page.tsx: Enhanced with refresh controls, better styling, wallet chart
|
||||
239→ 239→- ESLint passes clean
|
||||
240→ 240→
|
||||
241→ 241→---
|
||||
242→ 242→Task ID: 5-c
|
||||
243→ 243→Agent: List Pages Agent
|
||||
244→ 244→Task: Improve styling and features for all list pages
|
||||
245→ 245→
|
||||
246→ 246→
|
||||
247→ 247→Work Log:
|
||||
248→ 248→- Added page-enter animation to all 5 list pages
|
||||
249→ 249→- Added subtitle descriptions with counts
|
||||
250→ 250→- Standardized table wrapper with max-h and rounded-lg border
|
||||
251→ 251→- Added font-mono text-xs to ID columns
|
||||
252→ 252→- Added whitespace-nowrap to status badge columns
|
||||
253→ 253→- Improved empty states with consistent pattern
|
||||
254→ 254→- Users page: numbered pagination with ellipsis
|
||||
255→ 255→- Purchases page: Tabs with per-status counts
|
||||
256→ 256→- Audit page: action type filter dropdown
|
||||
257→ 257→- Categories page: debounced search
|
||||
258→ 258→- Locations page: debounced search
|
||||
259→ 259→
|
||||
260→ 260→Stage Summary:
|
||||
261→ 261→- 5 page components enhanced with better styling and new features
|
||||
262→ 262→- ESLint passes clean
|
||||
263→ 263→
|
||||
264→ 264→---
|
||||
265→ 265→Task ID: 5-d
|
||||
266→ 266→Agent: Detail Pages Agent
|
||||
267→ 267→Task: Improve wallets and user-detail pages
|
||||
268→ 268→
|
||||
269→ 269→Work Log:
|
||||
270→ 270→- Added page-enter animation to both pages
|
||||
271→ 271→- Added search filter to wallets page
|
||||
272→ 272→- Added status filter badges to wallets page
|
||||
273→ 273→- Added back button and KPI summary cards to user detail
|
||||
274→ 274→- Added tabs (Purchases/Wallets/Activity) to user detail
|
||||
275→ 275→- Added audit log userId filtering support
|
||||
276→ 276→- Improved empty states
|
||||
277→ 277→- Improved record payment dialog spacing
|
||||
278→ 278→
|
||||
279→ 279→Stage Summary:
|
||||
280→ 280→- 2 page components significantly enhanced
|
||||
281→ 281→- 1 API route updated
|
||||
282→ 282→- ESLint passes clean
|
||||
283→ 283→
|
||||
284→ 284→---
|
||||
285→ 285→Task ID: 6-a (Round 2)
|
||||
286→ 286→Agent: Features Agent
|
||||
287→ 287→Task: Add notifications panel, quick actions, clock, enhanced command palette
|
||||
288→ 288→
|
||||
289→ 289→
|
||||
290→ 290→Work Log:
|
||||
291→ 291→- Created quick-actions.tsx
|
||||
292→ 292→- Added real-time clock to header
|
||||
293→ 293→- Enhanced command palette with footer, dividers, keyboard hints
|
||||
294→ 294→- Created notifications-panel.tsx
|
||||
295→ 295→- Integrated into admin-header.tsx
|
||||
296→ 296→
|
||||
297→ 297→Stage Summary:
|
||||
298→ 298→- 2 new components, 2 enhanced
|
||||
299→ 299→- ESLint passes clean
|
||||
300→ 300→
|
||||
301→ 301→---
|
||||
302→ 302→Task ID: 4-a
|
||||
303→ 303→Agent: Bug Fix Agent
|
||||
304→ 304→Task: 12 targeted bug fixes
|
||||
305→ 305→
|
||||
306→ 306→Work Log:
|
||||
307→ 307→- Fixed dark theme badge colors across wallets/user-detail
|
||||
308→ 308→- Fixed command palette role leak
|
||||
309→ 309→- Fixed notifications count mismatch
|
||||
310→ 310→- Fixed catalog page-enter + duplicate title
|
||||
311→ 311→- Fixed login role demotion fallback
|
||||
312→ 312→- Changed admin123 to changeme
|
||||
313→ 313→- Added secure cookie flag
|
||||
314→ 314→- Made logout async with try/catch
|
||||
315→ 315→- Added JSON export option
|
||||
316→ 316→- Removed duplicate page titles
|
||||
317→ 317→- Added purchase status management
|
||||
318→ 318→- Added ErrorBoundary
|
||||
319→ 319→
|
||||
320→ 320→Stage Summary:
|
||||
321→ 321→- 10 files modified
|
||||
322→ 322→- ESLint: 0 errors, 0 warnings
|
||||
323→ 323→
|
||||
324→ 324→---
|
||||
325→ 325→Task ID: 4-b
|
||||
326→ 326→Agent: Purchase Status Agent
|
||||
327→ 327→Task: Purchase approve/cancel with API + UI
|
||||
328→ 328→
|
||||
329→ 329→Stage Summary:
|
||||
330→ 330→- 1 new API route, 1 file modified
|
||||
331→ 331→- ESLint: 0 errors
|
||||
332→ 332→
|
||||
333→ 333→---
|
||||
334→ 334→Task ID: 4-c
|
||||
335→ 335→Agent: Filter Agent
|
||||
336→ 336→Task: Date range filtering + audit search
|
||||
337→ 337→
|
||||
338→ 338→Stage Summary:
|
||||
339→ 339→- 4 files modified
|
||||
340→ 340→- ESLint: 0 errors
|
||||
341→ 341→
|
||||
342→ 342→---
|
||||
343→ 343→Task ID: 4-d
|
||||
344→ 344→Agent: Shared Utilities Agent
|
||||
345→ 345→Task: Pagination, useDebounce, ErrorBoundary
|
||||
346→ 346→
|
||||
347→ 347→Stage Summary:
|
||||
348→ 348→- 3 new files, 3 modified
|
||||
349→ 349→- ESLint: 0 errors
|
||||
350→ 350→
|
||||
351→ 351→---
|
||||
352→ 352→Task ID: 5-e
|
||||
353→ 353→Agent: Header Polish Agent
|
||||
354→ 354→Task: Logout confirmation dialog
|
||||
355→ 355→
|
||||
356→ 356→Stage Summary:
|
||||
357→ 357→- 1 file modified
|
||||
358→ 358→- ESLint: 0 errors
|
||||
359→ 359→
|
||||
360→ 360→---
|
||||
361→ 361→Task ID: 6-a
|
||||
362→ 362→Agent: Dashboard Enhancement Agent
|
||||
363→ 363→Task: More KPIs, donut chart, recent purchases
|
||||
364→ 364→
|
||||
365→ 365→Stage Summary:
|
||||
366→ 366→- 2 files modified
|
||||
367→ 367→- ESLint: 0 errors
|
||||
368→ 368→
|
||||
369→ 369→---
|
||||
370→ 370→Task ID: 6-b
|
||||
371→ 371→Agent: Users Enhancement Agent
|
||||
372→ 372→Task: Users tabs, user notes, region column
|
||||
373→ 373→
|
||||
374→ 374→Stage Summary:
|
||||
375→ 375→- Schema change, 2 APIs modified, 2 pages enhanced
|
||||
376→ 376→- ESLint: 0 errors
|
||||
377→ 377→
|
||||
378→ 378→---
|
||||
379→ 379→Task ID: 6-c
|
||||
380→ 380→Agent: Enhancement Agent
|
||||
381→ 381→Task: Wallet chart, settings backup/restore
|
||||
382→ 382→
|
||||
383→ 383→Stage Summary:
|
||||
384→ 384→- 2 new APIs, 2 pages modified
|
||||
385→ 385→- ESLint: 0 errors
|
||||
386→ 386→
|
||||
387→ 387→---
|
||||
388→ 388→Task ID: 7-a
|
||||
389→ 389→Agent: Footer + CSS Polish Agent
|
||||
390→ 390→Task: Footer, dark-mode fixes, CSS enhancements
|
||||
391→ 391→
|
||||
392→ 392→Stage Summary:
|
||||
393→ 393→- 1 new component, 4 files modified
|
||||
394→ 394→- ESLint: 0 errors
|
||||
395→ 395→
|
||||
396→ 396→---
|
||||
397→ 397→Task ID: 7-b
|
||||
398→ 398→Agent: Keyboard Shortcuts Agent
|
||||
399→ 399→Task: Keyboard shortcuts + sidebar hints
|
||||
400→ 400→
|
||||
401→ 401→Stage Summary:
|
||||
402→ 402→- 1 new hook, 2 files modified
|
||||
403→ 403→- ESLint: 0 errors
|
||||
404→ 404→
|
||||
405→ 405→---
|
||||
406→ 406→Task ID: 7-c
|
||||
407→ 407→Agent: Dashboard Sparklines + Seed/Locales Agent
|
||||
408→ 408→Task: Sparklines, seed visual overhaul, locales search
|
||||
409→ 409→
|
||||
410→ 410→Stage Summary:
|
||||
411→ 411→- 3 files modified
|
||||
412→ 412→- ESLint: 0 errors
|
||||
413→ 413→
|
||||
414→ 414→---
|
||||
415→ 415→Task ID: 7-d
|
||||
416→ 416→Agent: Settings Overhaul Agent
|
||||
417→ 417→Task: Settings visual overhaul with descriptions
|
||||
418→ 418→
|
||||
419→ 419→Stage Summary:
|
||||
420→ 420→- 2 files modified
|
||||
421→ 421→- ESLint: 0 errors
|
||||
422→ 422→
|
||||
423→ 423→---
|
||||
424→ 424→Task ID: 8
|
||||
425→ 425→Agent: Main Coordinator + 3 subagents
|
||||
426→ 426→Task: Branded loading, purchase detail modal, catalog enhancements, global search, transactions tab, audit copy, categories view, dashboard analytics, 404 page, empty state gradients
|
||||
427→ 427→
|
||||
428→ 428→
|
||||
429→ 429→Work Log:
|
||||
430→ 430→- Task 8-a: Branded loading screen with TS logo, progress bar, gradient orbs
|
||||
431→ 431→- Task 8-a: Purchase detail modal in user detail page with copy TX hash
|
||||
432→ 432→- Task 8-a: Catalog tree color accents by product count, stock indicators, summary bar
|
||||
433→ 433→- Task 8-a: Global user search in command palette (debounced, 2+ chars)
|
||||
434→ 434→- Task 8-b: New transactions/bulk API route
|
||||
435→ 435→- Task 8-b: 4th tab in wallets page with full transaction history
|
||||
436→ 436→- Task 8-b: Copy All + per-row Copy JSON buttons on audit page
|
||||
437→ 437→- Task 8-b: Categories quick view dialog showing products
|
||||
438→ 438→- Task 8-c: Dashboard 30-day revenue trend AreaChart
|
||||
439→ 439→- Task 8-c: Dashboard user funnel horizontal BarChart
|
||||
440→ 440→- Task 8-c: Enhanced 404 page with search icon and Go to Dashboard button
|
||||
441→ 441→- Task 8-c: Sidebar logo hover scale-110 micro-interaction
|
||||
442→ 442→- Task 8-c: empty-state radial gradient CSS class applied to 8 empty states
|
||||
443→ 443→
|
||||
444→ 444→
|
||||
445→ 445→Stage Summary:
|
||||
446→ 446→- 1 new API route (transactions/bulk), 1 products/bulk updated
|
||||
447→ 447→- 10 page components modified
|
||||
448→ 448→- 2 shared components modified (command-palette, admin-sidebar)
|
||||
449→ 449→- 1 global CSS enhancement (loading keyframe, empty-state class)
|
||||
450→ 450→- ESLint: 0 errors, 0 warnings
|
||||
451→ 451→
|
||||
452→ 452→---
|
||||
453→ 453→Task ID: 9-a
|
||||
454→ 454→Agent: Frontend Styling Expert
|
||||
455→ 455→Task: Comprehensive CSS and layout styling improvements
|
||||
456→ 456→
|
||||
457→ 457→Work Log:
|
||||
458→ 458→- **globals.css**: Added ~265 lines of new CSS utilities and animations
|
||||
459→ 459→ - Animated gradient border effect on focused inputs (gradientBorder keyframes with rotating oklch colors)
|
||||
460→ 460→ - `.glass-card` utility class for glassmorphism (backdrop-blur, semi-transparent bg, dark mode variant)
|
||||
461→ 461→ - `.page-section-enter` staggered section reveal animation (6 children, 60ms delay increments)
|
||||
462→ 462→ - `.stat-value` class with tabular-nums, font-variant-numeric, letter-spacing
|
||||
463→ 463→ - `.glow-success`, `.glow-warning`, `.glow-danger` subtle glow effects (different radii for light/dark)
|
||||
464→ 464→ - Improved `::selection` styling with warm orange accent and dark mode variant
|
||||
465→ 465→ - `.bg-noise` SVG noise texture overlay class with light/dark opacity variants
|
||||
466→ 466→ - `.ring-accent` focus ring variant
|
||||
467→ 467→ - `.kpi-shimmer` hover shimmer animation for cards (diagonal gradient sweep)
|
||||
468→ 468→ - `.count-up` number entry animation
|
||||
469→ 469→ - `.colon-pulse` clock colon separator animation
|
||||
470→ 470→ - `.gradient-border-b` / `.gradient-border-t` fade-in gradient borders for header/footer
|
||||
471→ 471→ - `.alternate-rows` table even-row background and first-column left border
|
||||
472→ 472→ - `.table-header-gradient` subtle gradient on thead
|
||||
473→ 473→ - `.sidebar-indicator-dot` pulsing dot animation
|
||||
474→ 474→ - Improved tbody tr hover with box-shadow inset accent
|
||||
475→ 475→- **admin-sidebar.tsx**: 5 styling improvements
|
||||
476→ 476→ - Active nav item left-border accent (2px, sidebar-primary color) via data-active
|
||||
477→ 477→ - Icon color transition on hover (muted → primary) on all nav items
|
||||
478→ 478→ - Animated pulsing indicator dot on Purchases item when pending count > 0
|
||||
479→ 479→ - Polished footer: ring on avatar, improved spacing (px-3 py-2), mt-0.5 on badge
|
||||
480→ 480→ - Connection indicator: smaller dot (1.5), glow-success class, improved opacity
|
||||
481→ 481→- **admin-header.tsx**: 3 improvements
|
||||
482→ 482→ - Gradient bottom border (transparent → border → transparent) via gradient-border-b class
|
||||
483→ 483→ - Backdrop-blur-md with bg-background/80 for translucent header
|
||||
484→ 484→ - Pulsing colon separator in RealtimeClock component (colon-pulse animation)
|
||||
485→ 485→- **admin-footer.tsx**: 4 improvements
|
||||
486→ 486→ - Gradient top border matching header via gradient-border-t
|
||||
487→ 487→ - Hover color transitions on text elements
|
||||
488→ 488→ - Improved spacing (py-3, gap-2) and text sizing (11px for tech stack)
|
||||
489→ 489→ - Semi-transparent text variants for visual hierarchy
|
||||
490→ 490→- **dashboard-page.tsx**: 4 improvements
|
||||
491→ 491→ - KPI cards: added kpi-shimmer hover effect, stat-value + count-up classes
|
||||
492→ 492→ - ChartCard: added optional icon prop with accent color, renders icon next to title
|
||||
493→ 493→ - All 8 ChartCard usages now pass appropriate icons (TrendingUp, Users, Package, etc.)
|
||||
494→ 494→ - Recent purchases table: alternate-rows + table-header-gradient classes
|
||||
495→ 495→- **users-page.tsx**: Table improvements
|
||||
496→ 496→ - Added alternate-rows + table-header-gradient classes to Table
|
||||
497→ 497→ - First column (ID) gets subtle left border accent (border-l-2 border-l-primary/10)
|
||||
498→ 498→- **purchases-page.tsx**: Table improvements
|
||||
499→ 499→ - Added alternate-rows + table-header-gradient classes to Table
|
||||
500→ 500→ - First column (ID) gets subtle left border accent (border-l-2 border-l-primary/10)
|
||||
501→ 501→
|
||||
502→ 502→Stage Summary:
|
||||
503→ 503→- 7 files modified (globals.css, admin-sidebar, admin-header, admin-footer, dashboard-page, users-page, purchases-page)
|
||||
504→ 504→- ~265 lines of new CSS, ~50 lines of TSX changes
|
||||
505→ 505→- ESLint: 0 errors, 0 warnings
|
||||
506→ 506→
|
||||
507→ 507→---
|
||||
508→ 508→Task ID: 9-b
|
||||
509→ 509→Agent: Feature Implementation Agent
|
||||
510→ 510→Task: 6 feature additions — batch actions, activity feed, product clone, timeline, wallet summary
|
||||
511→ 511→
|
||||
512→ 512→Work Log:
|
||||
513→ 513→- **1. Users Batch Actions** (users-page.tsx + API route)
|
||||
514→ 514→ - Added Checkbox import from shadcn/ui, ShieldBan/ShieldCheck icons from lucide-react, toast from sonner
|
||||
515→ 515→ - Added `selectedIds` (Set<number>) and `batchLoading` state
|
||||
516→ 516→ - Added `toggleSelect()`, `toggleSelectAll()`, `handleBatchStatus()` functions
|
||||
517→ 517→ - Added checkbox column (first column) with "Select All" in header
|
||||
518→ 518→ - Added floating action bar at bottom: selected count, Ban/Unban buttons, Clear button
|
||||
519→ 519→ - Floating bar uses `animate-in slide-in-from-bottom-4 fade-in` with backdrop-blur
|
||||
520→ 520→ - Created `src/app/api/users/batch-status/route.ts` — POST with {userIds, newStatus}, uses updateMany
|
||||
521→ 521→
|
||||
522→ 522→- **2. Purchases Batch Actions** (purchases-page.tsx + API route)
|
||||
523→ 523→ - Added Checkbox import, CheckCircle2/XCircle2 icons
|
||||
524→ 524→ - Added `selectedIds`, `batchLoading` state and toggle/batch functions
|
||||
525→ 525→ - Added checkbox column with "Select All" in header
|
||||
526→ 526→ - Added floating action bar: selected count, Approve/Cancel buttons, Clear button
|
||||
527→ 527→ - Created `src/app/api/purchases/batch-status/route.ts` — POST with {purchaseIds, status}, only updates pending
|
||||
528→ 528→
|
||||
529→ 529→- **3. Dashboard Activity Feed Improvements** (activity-feed.tsx + dashboard API)
|
||||
530→ 530→ - Modified `src/app/api/stats/dashboard/route.ts` to return `recentActivity` (last 8 audit logs)
|
||||
531→ 531→ - Changed from fetching `/api/audit/bulk` to using dashboard's `recentActivity` field
|
||||
532→ 532→ - Added per-action icon mapping with 15 action types (login, balance_adjust, user_banned, etc.)
|
||||
533→ 533→ - Added color-coded action badges with outline variant (bg-*/15 text-*/400 border-*/25)
|
||||
534→ 534→ - Improved relative time: "X seconds/minutes/hours/days/months ago" with proper pluralization
|
||||
535→ 535→ - Added staggered enter animation (50ms per item, fade-in + slide-in-from-left-1)
|
||||
536→ 536→ - Increased max height from h-48 to h-64 for more items visible
|
||||
537→ 537→
|
||||
538→ 538→- **4. Product Clone Feature** (catalog-page.tsx + API route)
|
||||
539→ 539→ - Added Copy icon import from lucide-react
|
||||
540→ 540→ - Added `handleCloneProduct()` function that POSTs to clone API
|
||||
541→ 541→ - Added Duplicate button (Copy icon, orange color) between Edit and Delete buttons on each product row
|
||||
542→ 542→ - Created `src/app/api/products/[id]/clone/route.ts` — POST, copies all fields, appends " (Copy)" to name
|
||||
543→ 543→ - Success toast: "Product cloned as \"{name} (Copy)\""
|
||||
544→ 544→
|
||||
545→ 545→- **5. User Detail Activity Timeline** (user-detail-page.tsx)
|
||||
546→ 546→ - Replaced table layout with vertical timeline (absolute left border line, colored dots)
|
||||
547→ 547→ - Added `actionDotColor()` helper — maps action types to Tailwind bg-* colors
|
||||
548→ 548→ - Added `relativeTime()` helper for compact time display ("3m ago", "2h ago")
|
||||
549→ 549→ - Added `expandedTimelineId` state for expandable details
|
||||
550→ 550→ - Each entry: colored dot (ring-4 ring-background), ActionBadge, relative time, chevron toggle
|
||||
551→ 551→ - Clicking expands: shows details in `<pre>` block with full date, with animation
|
||||
552→ 552→ - Added `ChevronDown`/`ChevronRight` icons for expand/collapse indicators
|
||||
553→ 553→ - Staggered entry animation (30ms per item)
|
||||
554→ 554→
|
||||
555→ 555→- **6. Wallets Balance Summary Cards** (wallets-page.tsx + overview API)
|
||||
556→ 556→ - Modified `src/app/api/wallets/overview/route.ts` to include `activeWallets` count
|
||||
557→ 557→ - Added `activeWallets` to OverviewData interface
|
||||
558→ 558→ - Added 3 glass-card mini cards at top of Owner Summary tab:
|
||||
559→ 559→ - Total Balance (DollarSign icon, orange, stat-value formatting)
|
||||
560→ 560→ - Total Wallets (Wallet icon, violet)
|
||||
561→ 561→ - Active Wallets (Wallet icon, emerald, with percentage of total)
|
||||
562→ 562→ - Uses existing `.glass-card` + `.stat-value` CSS classes
|
||||
563→ 563→
|
||||
564→ 564→Stage Summary:
|
||||
565→ 565→- 3 new API routes created (users/batch-status, purchases/batch-status, products/[id]/clone)
|
||||
566→ 566→- 1 API route modified (wallets/overview)
|
||||
567→ 567→- 6 page components modified (users-page, purchases-page, activity-feed, catalog-page, user-detail-page, wallets-page)
|
||||
568→ 568→- 1 dashboard API modified (stats/dashboard)
|
||||
569→ 569→- ESLint: 0 errors, 0 warnings
|
||||
570→ 570→
|
||||
571→ 571→---
|
||||
572→ 572→Task ID: 9-c
|
||||
573→ 573→Agent: Main Coordinator
|
||||
574→ 574→Task: QA Round 6 — Code review, bug fixes, styling, features
|
||||
575→ 575→
|
||||
576→ 576→Work Log:
|
||||
577→ 577→- Performed comprehensive code review QA via Explore subagent — found 24 bugs (2 critical, 5 high, 9 medium, 8 low)
|
||||
578→ 578→- Fixed 9 bugs directly (Settings PUT no-op, audit userId filter, product DELETE safety, CSV export, rate limiter leak, catalog res.ok, quick actions role, command palette nav, "use server" in API route)
|
||||
579→ 579→- Launched frontend-styling-expert subagent for comprehensive CSS/layout styling (~265 lines new CSS, 7 files modified)
|
||||
580→ 580→- Launched full-stack-developer subagent for 6 new features (batch actions×2, activity feed, product clone, timeline, wallet summary)
|
||||
581→ 581→- Fixed runtime compilation error (XCircle2 not in lucide-react → replaced with Ban)
|
||||
582→ 582→- Verified: ESLint 0 errors, GET / 200 (8.0s compile)
|
||||
583→ 583→
|
||||
584→ 584→Stage Summary:
|
||||
585→ 585→- 9 bug fixes across 8 files
|
||||
586→ 586→- 6 new features (3 new API routes, 7 modified components)
|
||||
587→ 587→- Comprehensive styling overhaul (7 files, ~265 lines CSS)
|
||||
588→ 588→- Total: 128+ source files, 40 API routes
|
||||
589→ 589→- ESLint: 0 errors, 0 warnings
|
||||
590→ 590→- Compile: GET / 200 verified
|
||||
591→ 591→
|
||||
592→ 592→---
|
||||
593→ 593→Task ID: 10-a
|
||||
594→ 594→Agent: API Routes Agent
|
||||
595→ 595→Task: Chatbot settings, leads, chat, operator API routes
|
||||
596→ 596→
|
||||
597→ 597→Work Log:
|
||||
598→ 598→- Created `src/lib/chatbot-config.ts` — shared 5-minute cache module for chatbot settings (reads from SiteSetting, used by admin/chatbot and chat routes)
|
||||
599→ 599→- Created `src/app/api/admin/chatbot/route.ts` — GET returns all 12 chatbot settings with defaults, masks API key (sk-xx****xxxx pattern); PUT validates temperature (0-2), max_tokens (50-4000), max_history (1-50), provider (openai|deepseek|openrouter|ollama|custom), upserts in transaction, skips masked values, clears cache
|
||||
600→ 600→- Created `src/app/api/leads/bulk/route.ts` — GET with pagination (page/limit), search across name/phone/email/telegram/telegramId, status filter, _count chatSessions, default sort by createdAt desc
|
||||
601→ 601→- Created `src/app/api/leads/[id]/route.ts` — GET returns lead with chatSessions (id, sessionId, isActive, createdAt, customerProfile); PUT updates status/notes/customFields with validation, writes audit log
|
||||
602→ 602→- Created `src/app/api/leads/[id]/sessions/route.ts` — GET returns all chat sessions for a lead with parsed messages JSON array
|
||||
603→ 603→- Created `src/app/api/chat/route.ts` — POST for TG bot integration: finds/creates ChatSession, loads chatbot config via cached getChatbotConfig, builds system prompt (system_prompt + knowledge_base + customer profile + catalog context from products DB), handles sleep mode, calls LLM via z-ai-web-dev-sdk `llm_chat` function, saves user+assistant messages, extracts lead data via regex (name/phone/email/telegram), generates customer profile (intent/interests/sentiment/readiness/summary), auto-creates/updates Lead record, returns reply with sessionId/leadId/profile. Graceful fallback if SDK fails.
|
||||
604→ 604→- Created `src/app/api/operator/route.ts` — POST connect (autoReplyDisabled=true, operatorName, operatorConnectedAt) / disconnect (clear), with audit log
|
||||
605→ 605→
|
||||
606→ 606→Stage Summary:
|
||||
607→ 607→- 6 new API routes + 1 shared lib (chatbot-config.ts)
|
||||
608→ 608→- Total: 879 lines across 7 files
|
||||
609→ 609→- ESLint: 0 errors, 0 warnings on new files
|
||||
610→ 610→- All routes use getAuth from @/lib/auth-middleware
|
||||
611→ 611→- Named exports (GET/POST/PUT), try/catch error handling
|
||||
612→ 612→- z-ai-web-dev-sdk used only in chat route
|
||||
613→ 613→
|
||||
614→ 614→---
|
||||
615→ 615→Task ID: 10-b
|
||||
616→ 616→Agent: Frontend Agent
|
||||
617→ 617→Task: Chatbot settings page, leads management page, matrix rain, sidebar nav, routing
|
||||
618→ 618→
|
||||
619→ 619→Work Log:
|
||||
620→ 620→- **globals.css**: Added ~33 lines of Matrix Rain CSS (`.matrix-rain` with `::before`/`::after` pseudo-elements, `matrixFall`/`matrixFall2` keyframes, dark mode variant with increased opacity)
|
||||
621→ 621→- **login/page.tsx**: Added `<div className="matrix-rain" />` after opening container div, before gradient mesh background
|
||||
622→ 622→- **chatbot-settings-page.tsx**: Created comprehensive 4-tab chatbot settings page (NEW FILE, ~280 lines)
|
||||
623→ 623→ - Tab 1 "Общие": Bot enabled switch, sleep mode switch with description, sleep message textarea, system prompt textarea (6 rows), welcome message textarea (3 rows)
|
||||
624→ 624→ - Tab 2 "Параметры ИИ": Temperature slider (0-2, step 0.1) with live value badge, Max Tokens number input (50-4000), Max History number input (1-50) with description
|
||||
625→ 625→ - Tab 3 "База знаний": Large textarea (12 rows) for knowledge base with placeholder showing markdown-style format, description card
|
||||
626→ 626→ - Tab 4 "Провайдер": Provider select (openai/deepseek/openrouter/ollama/custom), API endpoint input, API key password input with security note
|
||||
627→ 627→ - Save button at bottom of each card section, loading skeleton on mount, toast on success/error
|
||||
628→ 628→ - All text in Russian, glass-card styling, page-enter animation, proper dark theme
|
||||
629→ 629→- **leads-page.tsx**: Created full leads management page with split view (NEW FILE, ~580 lines)
|
||||
630→ 630→ - Left panel: search input with Search icon, 6 status filter buttons (Все/Новые/Контакты/Квалифиц./Потерянные/Спам), data table with 8 columns (Имя with avatar, Telegram, Телефон, Email, Статус badge, AI Скор %, Сессий count, Дата)
|
||||
631→ 631→ - Status badges: opacity-based colors per status (blue/amber/emerald/red/zinc)
|
||||
632→ 632→ - AI Score color coding: ≥70% emerald, ≥40% amber, <40% red
|
||||
633→ 633→ - Right panel (Sheet): lead info header with avatar/name/status badge/operator badge, created date
|
||||
634→ 634→ - Contact info card (TG/Phone/Email), AI Profile card (intent/interests/sentiment/readiness with color-coded badges, summary)
|
||||
635→ 635→ - Notes textarea with save button, status quick-change buttons, operator actions ("Взять чат" / "Передать боту")
|
||||
636→ 636→ - Chat sessions: expandable list, each session shows messages as chat bubbles (user left-aligned bg-muted, bot right-aligned bg-primary/10), rounded corners, timestamps
|
||||
637→ 637→ - API integration: GET /api/leads/bulk with pagination/search/status, GET /api/leads/{id}, GET /api/leads/{id}/sessions, PUT /api/leads/{id}, POST /api/operator
|
||||
638→ 638→ - Uses shared Pagination component, glass-card styling, empty state, loading skeletons
|
||||
639→ 639→- **admin-sidebar.tsx**: Added 2 new nav items to manageNav: "AI Chatbot" (Bot icon, /chatbot) and "Leads" (Target icon, /leads)
|
||||
640→ 640→- **page.tsx**: Added imports for ChatbotSettingsPage and LeadsPage, added route cases for #/chatbot and #/leads
|
||||
641→ 641→
|
||||
642→ 642→Stage Summary:
|
||||
643→ 643→- 2 new page components (chatbot-settings-page.tsx, leads-page.tsx)
|
||||
644→ 644→- 4 files modified (globals.css, login/page.tsx, admin-sidebar.tsx, page.tsx)
|
||||
645→ 645→- ESLint: 0 errors, 0 warnings on new/modified files (only pre-existing keepalive.js errors)
|
||||
646→ 646→- Dev log: GET / 200 in 62ms — compiles successfully
|
||||
647→ 647→- All text in Russian, dark theme compatible, named exports, 'use client' directive
|
||||
1514
tool-results/read_1786099467704_7b6cbd8dfb2e.txt
Normal file
1514
tool-results/read_1786099467704_7b6cbd8dfb2e.txt
Normal file
File diff suppressed because it is too large
Load Diff
30
worklog.md
30
worklog.md
@@ -644,4 +644,32 @@ Stage Summary:
|
||||
- 4 files modified (globals.css, login/page.tsx, admin-sidebar.tsx, page.tsx)
|
||||
- ESLint: 0 errors, 0 warnings on new/modified files (only pre-existing keepalive.js errors)
|
||||
- Dev log: GET / 200 in 62ms — compiles successfully
|
||||
- All text in Russian, dark theme compatible, named exports, 'use client' directive
|
||||
- All text in Russian, dark theme compatible, named exports, 'use client' directive---
|
||||
Task ID: 1
|
||||
Agent: Main
|
||||
Task: Sidebar cleanup, tabs styling, breadcrumbs fix, Ollama AI integration with language support
|
||||
|
||||
Work Log:
|
||||
- Removed extra Категории/Локации menu items from admin-sidebar.tsx, replaced with single "Каталог товаров" entry using FolderTree icon
|
||||
- Rewrote catalog-hub.tsx tabs — fixed grid/flex conflict, improved active tab styling with proper rounded-md transitions
|
||||
- Fixed critical breadcrumb bug: BreadcrumbSeparator (renders <li>) was nested inside BreadcrumbItem (also <li>), causing React error. Restructured using Fragment and separate mobile/desktop breadcrumb lists
|
||||
- Re-fixed groupedTree.keys bug in catalog-page.tsx — Map initialization moved before null guard (previous fix was lost in stash pop)
|
||||
- Added `language` field to ChatSession Prisma model (default "en")
|
||||
- Integrated Ollama Cloud API (https://ollama.com/v1/chat/completions) with API key b364c8...ge6
|
||||
- Added LANGUAGE_INSTRUCTIONS map (ru, en, es, ar, fr, de, zh, pt, tr, hi) — injected into system prompt before base prompt
|
||||
- Added `chatbot_model` setting to admin API and chatbot settings UI
|
||||
- Updated model selector with 18 real Ollama Cloud models (DeepSeek V4, Kimi K3, Gemma 4, etc.)
|
||||
- Fixed chatbot settings page: proper type conversion (string→boolean/number) when loading from API
|
||||
- Seeded Ollama credentials into database (enabled, sleep mode on, Ollama provider, correct endpoint)
|
||||
- Verified Ollama responses: Russian language → Russian reply, English → English reply
|
||||
|
||||
Stage Summary:
|
||||
- Sidebar: 1 catalog item instead of 3 ✅
|
||||
- Catalog tabs: properly styled and functional ✅
|
||||
- Breadcrumbs: no more nested <li> error ✅
|
||||
- groupedTree.keys: bug fixed (again) ✅
|
||||
- Ollama Cloud API: working with correct endpoint and models ✅
|
||||
- Language support: 10 languages, tested ru/en ✅
|
||||
- Chat API accepts `language` param from Telegram bot ✅
|
||||
- Sleep mode: re-enabled for shop-closed state ✅
|
||||
- ESLint: 0 errors ✅
|
||||
|
||||
Reference in New Issue
Block a user