vantuz 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,45 @@
1
+ VANTUZ AI SOFTWARE LICENSE AGREEMENT
2
+
3
+ Copyright (c) 2026 Nuri Can Avşar. All rights reserved.
4
+
5
+ This software and associated documentation files (the "Software") are licensed,
6
+ not sold. By installing, copying, or otherwise using the Software, you agree to
7
+ be bound by the terms of this agreement.
8
+
9
+ 1. LICENSE GRANT
10
+ Subject to the terms of this agreement and payment of applicable license fees,
11
+ Licensor grants you a limited, non-exclusive, non-transferable license to use
12
+ the Software for your internal business purposes.
13
+
14
+ 2. LICENSE KEY
15
+ A valid license key is required to use the Software. Each license key:
16
+ - Is valid for ONE (1) installation only
17
+ - Activates upon first use
18
+ - Expires 365 days after activation
19
+ - Cannot be shared, transferred, or resold
20
+
21
+ 3. RESTRICTIONS
22
+ You may NOT:
23
+ - Copy, modify, or distribute the Software
24
+ - Reverse engineer, decompile, or disassemble the Software
25
+ - Remove or alter any proprietary notices
26
+ - Share your license key with others
27
+ - Use the Software for illegal purposes
28
+
29
+ 4. INTELLECTUAL PROPERTY
30
+ The Software and all copies thereof are proprietary to Licensor and title
31
+ thereto remains exclusively with Licensor.
32
+
33
+ 5. TERMINATION
34
+ This license is effective until terminated. It will terminate automatically
35
+ if you fail to comply with any term of this agreement.
36
+
37
+ 6. WARRANTY DISCLAIMER
38
+ THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
39
+
40
+ 7. LIMITATION OF LIABILITY
41
+ IN NO EVENT SHALL LICENSOR BE LIABLE FOR ANY DAMAGES ARISING FROM USE
42
+ OF THE SOFTWARE.
43
+
44
+ For licensing inquiries: nuricanavsar2000@gmail.com
45
+ Website: https://nuricanavsar.com
package/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # 🐙 Vantuz AI
2
+
3
+ **Yapay Zeka Destekli E-Ticaret Yönetim Platformu**
4
+
5
+ 7 Türk pazaryerini tek platformdan yönetin: Trendyol, Hepsiburada, N11, Amazon, Çiçeksepeti, PTTavm, Pazarama
6
+
7
+ ## Kurulum
8
+
9
+ ```bash
10
+ npm install vantuz
11
+ ```
12
+
13
+ ## Hızlı Başlangıç
14
+
15
+ ```bash
16
+ # Yapılandırma
17
+ npx vantuz config
18
+
19
+ # Başlat
20
+ npx vantuz tui
21
+ ```
22
+
23
+ ## Özellikler
24
+
25
+ - 🏪 **7 Pazaryeri** - Tek komutla tüm platformları yönet
26
+ - 🤖 **Akıllı Fiyatlama** - Rakip takibi ve otomatik fiyat optimizasyonu
27
+ - 📊 **Hızlı Raporlar** - Anlık satış ve stok özeti
28
+ - ⏰ **Otomasyon** - Zamanlanmış görevler ve uyarılar
29
+ - 🧠 **Türkçe NL** - Doğal dil komut desteği
30
+
31
+ ## Komutlar
32
+
33
+ ```bash
34
+ npx vantuz tui # Sohbet modu
35
+ npx vantuz config # Ayarlar
36
+ npx vantuz status # Durum kontrolü
37
+ ```
38
+
39
+ ## Lisans
40
+
41
+ Ticari yazılım. Kullanım için lisans anahtarı gereklidir.
42
+
43
+ 📧 nuricanavsar2000@gmail.com
44
+ 🌐 https://nuricanavsar.com
package/cli.js ADDED
@@ -0,0 +1,420 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 🐙 VANTUZ CLI
4
+ * Terminal üzerinden Vantuz AI ile etkileşim
5
+ *
6
+ * Kullanım:
7
+ * vantuz tui → Sohbet modu
8
+ * vantuz config → Ayarları yapılandır
9
+ * vantuz status → Durum kontrolü
10
+ */
11
+
12
+ import fs from 'fs';
13
+ import path from 'path';
14
+ import { fileURLToPath } from 'url';
15
+ import readline from 'readline';
16
+
17
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
18
+ const CONFIG_PATH = path.join(__dirname, '.env');
19
+ const CONFIG_JSON = path.join(__dirname, 'vantuz.config.json');
20
+
21
+ // ═══════════════════════════════════════════════════════════════════════════
22
+ // RENK KODLARI
23
+ // ═══════════════════════════════════════════════════════════════════════════
24
+
25
+ const colors = {
26
+ reset: '\x1b[0m',
27
+ bold: '\x1b[1m',
28
+ dim: '\x1b[2m',
29
+ red: '\x1b[31m',
30
+ green: '\x1b[32m',
31
+ yellow: '\x1b[33m',
32
+ blue: '\x1b[34m',
33
+ magenta: '\x1b[35m',
34
+ cyan: '\x1b[36m',
35
+ white: '\x1b[37m',
36
+ bgBlue: '\x1b[44m',
37
+ bgMagenta: '\x1b[45m'
38
+ };
39
+
40
+ const c = (color, text) => `${colors[color]}${text}${colors.reset}`;
41
+
42
+ // ═══════════════════════════════════════════════════════════════════════════
43
+ // YARDIMCI FONKSİYONLAR
44
+ // ═══════════════════════════════════════════════════════════════════════════
45
+
46
+ function clearScreen() {
47
+ console.clear();
48
+ }
49
+
50
+ function printHeader() {
51
+ console.log(c('cyan', `
52
+ ╔═══════════════════════════════════════════════════════════╗
53
+ ║ 🐙 ${c('bold', 'VANTUZ AI')} - E-Ticaretin Yapay Zeka Beyni ║
54
+ ╚═══════════════════════════════════════════════════════════╝
55
+ `));
56
+ }
57
+
58
+ function loadConfig() {
59
+ try {
60
+ if (fs.existsSync(CONFIG_JSON)) {
61
+ return JSON.parse(fs.readFileSync(CONFIG_JSON, 'utf-8'));
62
+ }
63
+ } catch (e) { }
64
+ return {};
65
+ }
66
+
67
+ function saveConfig(config) {
68
+ fs.writeFileSync(CONFIG_JSON, JSON.stringify(config, null, 2));
69
+ }
70
+
71
+ function loadEnv() {
72
+ const env = {};
73
+ try {
74
+ if (fs.existsSync(CONFIG_PATH)) {
75
+ const content = fs.readFileSync(CONFIG_PATH, 'utf-8');
76
+ content.split('\n').forEach(line => {
77
+ const match = line.match(/^([^=]+)=(.*)$/);
78
+ if (match) {
79
+ env[match[1].trim()] = match[2].trim();
80
+ }
81
+ });
82
+ }
83
+ } catch (e) { }
84
+ return env;
85
+ }
86
+
87
+ function saveEnv(env) {
88
+ const lines = Object.entries(env).map(([k, v]) => `${k}=${v}`);
89
+ fs.writeFileSync(CONFIG_PATH, lines.join('\n'));
90
+ }
91
+
92
+ // ═══════════════════════════════════════════════════════════════════════════
93
+ // READLINE HELPER
94
+ // ═══════════════════════════════════════════════════════════════════════════
95
+
96
+ function createRL() {
97
+ return readline.createInterface({
98
+ input: process.stdin,
99
+ output: process.stdout
100
+ });
101
+ }
102
+
103
+ async function ask(rl, question, defaultValue = '') {
104
+ return new Promise(resolve => {
105
+ const prompt = defaultValue
106
+ ? `${question} ${c('dim', `[${defaultValue}]`)}: `
107
+ : `${question}: `;
108
+ rl.question(prompt, answer => {
109
+ resolve(answer.trim() || defaultValue);
110
+ });
111
+ });
112
+ }
113
+
114
+ async function askYesNo(rl, question, defaultYes = true) {
115
+ const hint = defaultYes ? '[E/h]' : '[e/H]';
116
+ const answer = await ask(rl, `${question} ${c('dim', hint)}`);
117
+ if (!answer) return defaultYes;
118
+ return answer.toLowerCase().startsWith('e') || answer.toLowerCase().startsWith('y');
119
+ }
120
+
121
+ // ═══════════════════════════════════════════════════════════════════════════
122
+ // CONFIG KOMUTU
123
+ // ═══════════════════════════════════════════════════════════════════════════
124
+
125
+ async function runConfig() {
126
+ clearScreen();
127
+ printHeader();
128
+
129
+ const rl = createRL();
130
+ const config = loadConfig();
131
+ const env = loadEnv();
132
+
133
+ console.log(c('yellow', ' ⚙️ Yapılandırma Sihirbazı'));
134
+ console.log(c('dim', ' Her adımda Enter = varsayılan, "skip" = atla\n'));
135
+
136
+ // AI Provider
137
+ console.log(c('cyan', '\n ═══ AI Sağlayıcı ═══'));
138
+ console.log(' 1) OpenAI (GPT-4)');
139
+ console.log(' 2) Anthropic (Claude)');
140
+ console.log(' 3) DeepSeek');
141
+ console.log(' 4) Groq');
142
+ console.log(' 5) Gemini');
143
+ console.log(' 6) Atla (skip)');
144
+
145
+ const aiChoice = await ask(rl, '\n Seçim', '1');
146
+ if (aiChoice !== '6' && aiChoice.toLowerCase() !== 'skip') {
147
+ const providers = ['openai', 'anthropic', 'deepseek', 'groq', 'gemini'];
148
+ config.aiProvider = providers[parseInt(aiChoice) - 1] || 'openai';
149
+
150
+ const keyMap = {
151
+ openai: 'OPENAI_API_KEY',
152
+ anthropic: 'ANTHROPIC_API_KEY',
153
+ deepseek: 'DEEPSEEK_API_KEY',
154
+ groq: 'GROQ_API_KEY',
155
+ gemini: 'GEMINI_API_KEY'
156
+ };
157
+
158
+ const envKey = keyMap[config.aiProvider];
159
+ const apiKey = await ask(rl, ` ${envKey}`, env[envKey] || '');
160
+ if (apiKey && apiKey !== 'skip') {
161
+ env[envKey] = apiKey;
162
+ }
163
+ }
164
+
165
+ // Platforms
166
+ console.log(c('cyan', '\n ═══ Pazaryeri Bağlantıları ═══'));
167
+ console.log(c('dim', ' Her platform için API bilgilerini girin veya "skip" yazın\n'));
168
+
169
+ const platforms = [
170
+ { name: 'Trendyol', keys: ['TRENDYOL_SUPPLIER_ID', 'TRENDYOL_API_KEY', 'TRENDYOL_API_SECRET'] },
171
+ { name: 'Hepsiburada', keys: ['HEPSIBURADA_MERCHANT_ID', 'HEPSIBURADA_USERNAME', 'HEPSIBURADA_PASSWORD'] },
172
+ { name: 'N11', keys: ['N11_API_KEY', 'N11_API_SECRET'] },
173
+ { name: 'Amazon', keys: ['AMAZON_SELLER_ID', 'AMAZON_CLIENT_ID', 'AMAZON_REFRESH_TOKEN'] },
174
+ { name: 'Çiçeksepeti', keys: ['CICEKSEPETI_API_KEY'] },
175
+ { name: 'PTTavm', keys: ['PTTAVM_API_KEY', 'PTTAVM_TOKEN'] },
176
+ { name: 'Pazarama', keys: ['PAZARAMA_CLIENT_ID', 'PAZARAMA_CLIENT_SECRET'] }
177
+ ];
178
+
179
+ for (const platform of platforms) {
180
+ const setup = await askYesNo(rl, ` ${platform.name} ayarla?`, false);
181
+ if (setup) {
182
+ for (const key of platform.keys) {
183
+ const value = await ask(rl, ` ${key}`, env[key] || '');
184
+ if (value && value !== 'skip') {
185
+ env[key] = value;
186
+ }
187
+ }
188
+ console.log(c('green', ` ✓ ${platform.name} ayarlandı\n`));
189
+ } else {
190
+ console.log(c('dim', ` → ${platform.name} atlandı\n`));
191
+ }
192
+ }
193
+
194
+ // Save
195
+ saveConfig(config);
196
+ saveEnv(env);
197
+
198
+ console.log(c('green', '\n ✅ Yapılandırma kaydedildi!'));
199
+ console.log(c('dim', ` → ${CONFIG_JSON}`));
200
+ console.log(c('dim', ` → ${CONFIG_PATH}`));
201
+ console.log(c('cyan', '\n Başlatmak için: vantuz tui\n'));
202
+
203
+ rl.close();
204
+ }
205
+
206
+ // ═══════════════════════════════════════════════════════════════════════════
207
+ // TUI (SOHBET MODU)
208
+ // ═══════════════════════════════════════════════════════════════════════════
209
+
210
+ async function runTUI() {
211
+ clearScreen();
212
+ printHeader();
213
+
214
+ const rl = createRL();
215
+ const config = loadConfig();
216
+ const env = loadEnv();
217
+
218
+ console.log(c('green', ' 💬 Sohbet Modu'));
219
+ console.log(c('dim', ' Komutlar: /help, /stok, /fiyat, /rapor, /cikis\n'));
220
+
221
+ // Check AI config
222
+ const hasAI = env.OPENAI_API_KEY || env.ANTHROPIC_API_KEY || env.DEEPSEEK_API_KEY;
223
+ if (!hasAI) {
224
+ console.log(c('yellow', ' ⚠️ AI sağlayıcı yapılandırılmamış.'));
225
+ console.log(c('dim', ' → vantuz config komutunu çalıştırın\n'));
226
+ }
227
+
228
+ // Chat loop
229
+ const prompt = () => {
230
+ rl.question(c('cyan', '\n Sen: '), async (input) => {
231
+ input = input.trim();
232
+
233
+ if (!input) {
234
+ prompt();
235
+ return;
236
+ }
237
+
238
+ // Commands
239
+ if (input.startsWith('/')) {
240
+ await handleCommand(input, config, env);
241
+ prompt();
242
+ return;
243
+ }
244
+
245
+ // AI Chat
246
+ console.log(c('magenta', '\n Vantuz: ') + await processChat(input, config, env));
247
+ prompt();
248
+ });
249
+ };
250
+
251
+ prompt();
252
+ }
253
+
254
+ async function handleCommand(input, config, env) {
255
+ const [cmd, ...args] = input.slice(1).split(' ');
256
+
257
+ switch (cmd.toLowerCase()) {
258
+ case 'help':
259
+ case 'yardim':
260
+ console.log(`
261
+ ${c('cyan', 'Komutlar:')}
262
+ /stok [platform] → Stok durumu
263
+ /fiyat <ürün> <tl> → Fiyat güncelle
264
+ /rapor [dönem] → Satış raporu
265
+ /platformlar → Bağlı platformlar
266
+ /config → Ayarları aç
267
+ /cikis → Çıkış
268
+ `);
269
+ break;
270
+
271
+ case 'stok':
272
+ console.log(c('yellow', '\n 📦 Stok kontrolü yapılıyor...'));
273
+ console.log(c('dim', ' (Bu özellik API bağlantısı gerektirir)'));
274
+ break;
275
+
276
+ case 'fiyat':
277
+ console.log(c('yellow', '\n 💰 Fiyat güncelleme...'));
278
+ console.log(c('dim', ` Hedef: ${args.join(' ')}`));
279
+ break;
280
+
281
+ case 'rapor':
282
+ console.log(c('yellow', '\n 📊 Rapor oluşturuluyor...'));
283
+ const period = args[0] || '7d';
284
+ console.log(c('dim', ` Dönem: ${period}`));
285
+ break;
286
+
287
+ case 'platformlar':
288
+ console.log(`
289
+ ${c('cyan', 'Platform Durumu:')}
290
+ 🟠 Trendyol: ${env.TRENDYOL_API_KEY ? c('green', '✓ Bağlı') : c('dim', '○ Ayarlanmamış')}
291
+ 🟣 Hepsiburada: ${env.HEPSIBURADA_MERCHANT_ID ? c('green', '✓ Bağlı') : c('dim', '○ Ayarlanmamış')}
292
+ 🔵 N11: ${env.N11_API_KEY ? c('green', '✓ Bağlı') : c('dim', '○ Ayarlanmamış')}
293
+ 🟡 Amazon: ${env.AMAZON_SELLER_ID ? c('green', '✓ Bağlı') : c('dim', '○ Ayarlanmamış')}
294
+ 🌸 Çiçeksepeti: ${env.CICEKSEPETI_API_KEY ? c('green', '✓ Bağlı') : c('dim', '○ Ayarlanmamış')}
295
+ 📮 PTTavm: ${env.PTTAVM_API_KEY ? c('green', '✓ Bağlı') : c('dim', '○ Ayarlanmamış')}
296
+ 🛒 Pazarama: ${env.PAZARAMA_CLIENT_ID ? c('green', '✓ Bağlı') : c('dim', '○ Ayarlanmamış')}
297
+ `);
298
+ break;
299
+
300
+ case 'config':
301
+ console.log(c('dim', '\n → Terminalde "vantuz config" yazın'));
302
+ break;
303
+
304
+ case 'cikis':
305
+ case 'exit':
306
+ case 'quit':
307
+ console.log(c('cyan', '\n 👋 Görüşmek üzere!\n'));
308
+ process.exit(0);
309
+
310
+ default:
311
+ console.log(c('red', ` ❌ Bilinmeyen komut: /${cmd}`));
312
+ console.log(c('dim', ' /help yazarak komutları görebilirsiniz'));
313
+ }
314
+ }
315
+
316
+ async function processChat(input, config, env) {
317
+ // Simple NL parsing
318
+ const lower = input.toLowerCase();
319
+
320
+ if (lower.includes('stok') && (lower.includes('düşük') || lower.includes('az'))) {
321
+ return 'Düşük stoklu ürünleri kontrol ediyorum... (API bağlantısı gerekli)';
322
+ }
323
+
324
+ if (lower.includes('fiyat') && lower.includes('güncelle')) {
325
+ return 'Fiyat güncellemesi için /fiyat <ürün> <tl> komutunu kullanın.';
326
+ }
327
+
328
+ if (lower.includes('sipariş') || lower.includes('order')) {
329
+ return 'Siparişleri kontrol ediyorum... (API bağlantısı gerekli)';
330
+ }
331
+
332
+ if (lower.includes('rapor')) {
333
+ return 'Rapor için /rapor 7d yazabilirsiniz.';
334
+ }
335
+
336
+ // Default response
337
+ if (!env.OPENAI_API_KEY && !env.ANTHROPIC_API_KEY) {
338
+ return 'AI yanıtı için API anahtarı gerekli. "vantuz config" ile ayarlayın.';
339
+ }
340
+
341
+ return 'Anladım! Bu işlem için pazaryeri API bağlantısı gerekiyor.';
342
+ }
343
+
344
+ // ═══════════════════════════════════════════════════════════════════════════
345
+ // STATUS KOMUTU
346
+ // ═══════════════════════════════════════════════════════════════════════════
347
+
348
+ async function runStatus() {
349
+ printHeader();
350
+
351
+ const config = loadConfig();
352
+ const env = loadEnv();
353
+
354
+ console.log(c('cyan', ' 📊 Sistem Durumu\n'));
355
+
356
+ // AI
357
+ const aiProvider = config.aiProvider || 'Ayarlanmamış';
358
+ const hasAIKey = env.OPENAI_API_KEY || env.ANTHROPIC_API_KEY;
359
+ console.log(` AI Sağlayıcı: ${aiProvider} ${hasAIKey ? c('green', '✓') : c('red', '✗')}`);
360
+
361
+ // Platforms
362
+ console.log('\n Platformlar:');
363
+ const platforms = [
364
+ ['Trendyol', 'TRENDYOL_API_KEY'],
365
+ ['Hepsiburada', 'HEPSIBURADA_MERCHANT_ID'],
366
+ ['N11', 'N11_API_KEY'],
367
+ ['Amazon', 'AMAZON_SELLER_ID'],
368
+ ['Çiçeksepeti', 'CICEKSEPETI_API_KEY'],
369
+ ['PTTavm', 'PTTAVM_API_KEY'],
370
+ ['Pazarama', 'PAZARAMA_CLIENT_ID']
371
+ ];
372
+
373
+ let connected = 0;
374
+ for (const [name, key] of platforms) {
375
+ const status = env[key] ? c('green', '✓ Bağlı') : c('dim', '○');
376
+ if (env[key]) connected++;
377
+ console.log(` ${name}: ${status}`);
378
+ }
379
+
380
+ console.log(`\n Toplam: ${connected}/${platforms.length} platform bağlı`);
381
+ console.log();
382
+ }
383
+
384
+ // ═══════════════════════════════════════════════════════════════════════════
385
+ // MAIN
386
+ // ═══════════════════════════════════════════════════════════════════════════
387
+
388
+ const args = process.argv.slice(2);
389
+ const command = args[0]?.toLowerCase();
390
+
391
+ switch (command) {
392
+ case 'tui':
393
+ case 'chat':
394
+ case 'sohbet':
395
+ runTUI();
396
+ break;
397
+
398
+ case 'config':
399
+ case 'ayar':
400
+ case 'setup':
401
+ runConfig();
402
+ break;
403
+
404
+ case 'status':
405
+ case 'durum':
406
+ runStatus();
407
+ break;
408
+
409
+ default:
410
+ printHeader();
411
+ console.log(`
412
+ ${c('yellow', 'Kullanım:')}
413
+
414
+ vantuz tui Sohbet modunu başlat
415
+ vantuz config Ayarları yapılandır
416
+ vantuz status Sistem durumunu göster
417
+
418
+ ${c('dim', 'İlk kullanımda: vantuz config')}
419
+ `);
420
+ }
@@ -0,0 +1,46 @@
1
+ const axios = require('axios');
2
+
3
+ module.exports = {
4
+ async analyze(data, config) {
5
+ if (!config.ai || !config.ai.apiKey) {
6
+ throw new Error('AI yapılandırması eksik. Ayarlardan API anahtarınızı girin.');
7
+ }
8
+
9
+ const prompt = `
10
+ Senin adın Vantuz. uzman e-ticaret analistisin.
11
+ Aşağıdaki e-ticaret verilerini analiz et ve mağaza sahibine 3 adet kritik, eyleme dönüştürülebilir öneri sun.
12
+ Yanıtın kısa, net ve profesyonel olsun. Türkçe yanıt ver.
13
+
14
+ Veriler:
15
+ ${JSON.stringify(data, null, 2)}
16
+ `;
17
+
18
+ try {
19
+ const baseURL = config.ai.baseUrl || 'https://api.openai.com/v1';
20
+ const model = config.ai.model || 'gpt-4-turbo';
21
+
22
+ // Generic OpenAI Compatible Endpoint Support (Works with DeepSeek, OpenAI, LocalAI)
23
+ const response = await axios.post(`${baseURL}/chat/completions`, {
24
+ model: model,
25
+ messages: [
26
+ { role: 'system', content: 'Sen uzman bir e-ticaret danışmanısın.' },
27
+ { role: 'user', content: prompt }
28
+ ],
29
+ temperature: 0.7
30
+ }, {
31
+ headers: {
32
+ 'Authorization': `Bearer ${config.ai.apiKey}`,
33
+ 'Content-Type': 'application/json'
34
+ }
35
+ });
36
+
37
+ return response.data.choices[0].message.content;
38
+
39
+ } catch (error) {
40
+ if (error.response) {
41
+ throw new Error(`AI API Hatası: ${error.response.status} - ${JSON.stringify(error.response.data)}`);
42
+ }
43
+ throw error;
44
+ }
45
+ }
46
+ };
@@ -0,0 +1,74 @@
1
+ const { Sequelize, DataTypes } = require('sequelize');
2
+ const path = require('path');
3
+ const fs = require('fs');
4
+
5
+ // Veritabanı dosyasının yolu (Kullanıcının home dizininde veya proje klasöründe)
6
+ const dbPath = path.join(process.cwd(), 'vantuz.sqlite');
7
+
8
+ const sequelize = new Sequelize({
9
+ dialect: 'sqlite',
10
+ storage: dbPath,
11
+ logging: false // Konsolu kirletmesin
12
+ });
13
+
14
+ // --- MODELLER ---
15
+
16
+ // Mağaza Ayarları (API Keyler vb.)
17
+ const Store = sequelize.define('Store', {
18
+ name: { type: DataTypes.STRING, allowNull: false },
19
+ platform: { type: DataTypes.STRING, allowNull: false }, // trendyol, amazon, etc.
20
+ credentials: { type: DataTypes.JSON, allowNull: false }, // { apiKey: '...', apiSecret: '...' }
21
+ isActive: { type: DataTypes.BOOLEAN, defaultValue: true }
22
+ });
23
+
24
+ // Ürünler
25
+ const Product = sequelize.define('Product', {
26
+ name: { type: DataTypes.STRING, allowNull: false },
27
+ barcode: { type: DataTypes.STRING, unique: true },
28
+ sku: { type: DataTypes.STRING },
29
+ description: { type: DataTypes.TEXT },
30
+ brand: { type: DataTypes.STRING },
31
+ images: { type: DataTypes.JSON }, // Resim URL'leri listesi
32
+ marketData: { type: DataTypes.JSON }, // { trendyol: { price: 100, stock: 10 }, amazon: { ... } }
33
+ aiAnalysis: { type: DataTypes.TEXT } // AI tarafından üretilen satış önerileri
34
+ });
35
+
36
+ // Siparişler
37
+ const Order = sequelize.define('Order', {
38
+ platform: { type: DataTypes.STRING, allowNull: false },
39
+ orderNumber: { type: DataTypes.STRING, unique: true },
40
+ customerName: { type: DataTypes.STRING },
41
+ totalAmount: { type: DataTypes.FLOAT },
42
+ currency: { type: DataTypes.STRING, defaultValue: 'TRY' },
43
+ status: { type: DataTypes.STRING },
44
+ orderDate: { type: DataTypes.DATE },
45
+ items: { type: DataTypes.JSON } // Sipariş içeriği
46
+ });
47
+
48
+ // Loglar ve AI Önerileri
49
+ const Insight = sequelize.define('Insight', {
50
+ type: { type: DataTypes.STRING }, // 'pricing', 'stock', 'trend'
51
+ message: { type: DataTypes.TEXT },
52
+ priority: { type: DataTypes.INTEGER }, // 1: Düşük, 5: Kritik
53
+ isRead: { type: DataTypes.BOOLEAN, defaultValue: false }
54
+ });
55
+
56
+ // Veritabanını Başlat
57
+ async function initDB() {
58
+ try {
59
+ await sequelize.sync({ alter: true }); // Tabloları güncelle
60
+ return true;
61
+ } catch (error) {
62
+ console.error('Veritabanı hatası:', error);
63
+ return false;
64
+ }
65
+ }
66
+
67
+ module.exports = {
68
+ sequelize,
69
+ Store,
70
+ Product,
71
+ Order,
72
+ Insight,
73
+ initDB
74
+ };
@@ -0,0 +1,50 @@
1
+ const crypto = require('crypto');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+ // Müşteriye Gidecek Olan PUBLIC KEY (Sadece doğrulama yapar)
6
+ const PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
7
+ MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy... (Buraya gerçek key gelecek)
8
+ -----END PUBLIC KEY-----`;
9
+
10
+ // NOT: Bu dosya artık lisans ÜRETEMEZ. Sadece doğrular.
11
+ // Lisans üretmek için 'admin-keygen.js' dosyasını kullanın (Müşteriye vermeyin).
12
+
13
+ module.exports = {
14
+ verifyLicense(licenseKey) {
15
+ try {
16
+ // Lisans formatı: BASE64_DATA.BASE64_SIGNATURE
17
+ const parts = licenseKey.split('.');
18
+ if (parts.length !== 2) return { valid: false, reason: 'Geçersiz Format' };
19
+
20
+ const data = parts[0];
21
+ const signature = parts[1];
22
+
23
+ // İmzayı doğrula
24
+ const verify = crypto.createVerify('SHA256');
25
+ verify.update(data);
26
+ verify.end();
27
+
28
+ // Gerçek Public Key'i okuyalım (Normalde hardcoded olur ama demo için dosyadan okuyorum)
29
+ const pubKey = fs.readFileSync(path.join(__dirname, '../public.pem'), 'utf8');
30
+
31
+ const isValid = verify.verify(pubKey, signature, 'base64');
32
+
33
+ if (!isValid) {
34
+ return { valid: false, reason: 'Sahte Lisans (İmza Geçersiz)' };
35
+ }
36
+
37
+ const payload = JSON.parse(Buffer.from(data, 'base64').toString('utf8'));
38
+ const today = new Date().toISOString().split('T')[0];
39
+
40
+ if (payload.expiry < today) {
41
+ return { valid: false, reason: 'Süresi Dolmuş Lisans' };
42
+ }
43
+
44
+ return { valid: true, data: payload };
45
+
46
+ } catch (e) {
47
+ return { valid: false, reason: 'Lisans Okunamadı' };
48
+ }
49
+ }
50
+ };