SaaS/database/init.js
Claude Code d1b5b72c46 🚀 Transform into full SaaS Automation Platform
Major Update: From simple click counter to comprehensive automation platform

## New Features:
 Full user authentication (register/login/logout)
 SQLite database with user management
 API credentials management system
 Workflow templates library (4 ready-to-use templates)
 User workflow management
 Comprehensive dashboard interface
 Detailed n8n integration instructions
 Security features (bcrypt, sessions, helmet)
 Automated testing suite (14 passing tests)

## Technical Stack:
- Backend: Node.js + Express + SQLite
- Frontend: Vanilla JS + Modern CSS
- Security: bcrypt, express-session, helmet
- Database: SQLite with proper schemas and indexes
- Testing: Mocha + Chai + Supertest

## Templates Included:
1. 📱 Telegram Bot Notifications
2. 📧 Email to Slack Integration
3. 💾 Google Drive Backup Automation
4. 📊 Lead Scoring Automation

## Access Points:
- Legacy app: http://localhost:3000/
- SaaS Platform: http://localhost:3000/dashboard
- API endpoints: /api/*

## Demo Credentials:
- Email: demo@example.com
- Password: demo123

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-29 11:05:29 +01:00

344 lines
No EOL
14 KiB
JavaScript

const sqlite3 = require('sqlite3').verbose();
const path = require('path');
const fs = require('fs');
const DB_PATH = path.join(__dirname, 'saas_platform.db');
// Создаем или открываем базу данных
const db = new sqlite3.Database(DB_PATH);
// Функция инициализации базы данных
function initDatabase() {
return new Promise((resolve, reject) => {
db.serialize(() => {
// Создание таблиц
db.run(`
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
email TEXT UNIQUE NOT NULL,
password_hash TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
is_active BOOLEAN DEFAULT 1,
subscription_type TEXT DEFAULT 'free'
)
`);
db.run(`
CREATE TABLE IF NOT EXISTS user_credentials (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
service_name TEXT NOT NULL,
credential_type TEXT NOT NULL,
encrypted_value TEXT NOT NULL,
description TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
is_active BOOLEAN DEFAULT 1,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
UNIQUE(user_id, service_name, credential_type)
)
`);
db.run(`
CREATE TABLE IF NOT EXISTS workflow_templates (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
description TEXT,
category TEXT,
template_data TEXT NOT NULL,
n8n_workflow_id TEXT,
required_credentials TEXT,
difficulty_level TEXT DEFAULT 'beginner',
estimated_setup_time INTEGER,
is_featured BOOLEAN DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
is_active BOOLEAN DEFAULT 1
)
`);
db.run(`
CREATE TABLE IF NOT EXISTS user_workflows (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
template_id INTEGER,
workflow_name TEXT NOT NULL,
n8n_workflow_id TEXT,
status TEXT DEFAULT 'draft',
configuration TEXT,
last_run_at DATETIME,
total_runs INTEGER DEFAULT 0,
successful_runs INTEGER DEFAULT 0,
failed_runs INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (template_id) REFERENCES workflow_templates(id) ON DELETE SET NULL
)
`);
db.run(`
CREATE TABLE IF NOT EXISTS usage_stats (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
workflow_id INTEGER,
action_type TEXT NOT NULL,
resource_usage INTEGER DEFAULT 1,
execution_time INTEGER,
status TEXT NOT NULL,
metadata TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (workflow_id) REFERENCES user_workflows(id) ON DELETE SET NULL
)
`);
// Создание индексов
db.run('CREATE INDEX IF NOT EXISTS idx_user_credentials_user_id ON user_credentials(user_id)');
db.run('CREATE INDEX IF NOT EXISTS idx_user_workflows_user_id ON user_workflows(user_id)');
db.run('CREATE INDEX IF NOT EXISTS idx_usage_stats_user_id ON usage_stats(user_id)');
db.run('CREATE INDEX IF NOT EXISTS idx_workflow_templates_category ON workflow_templates(category)');
db.run('CREATE INDEX IF NOT EXISTS idx_workflow_templates_featured ON workflow_templates(is_featured)');
// Вставка начальных данных
insertInitialData(() => {
console.log('✅ База данных инициализирована успешно');
resolve(db);
});
});
});
}
function insertInitialData(callback) {
// Вставка шаблонов рабочих процессов
const templates = [
{
name: 'Уведомления в Telegram',
description: 'Отправка уведомлений в Telegram при возникновении определенных событий',
category: 'notifications',
template_data: JSON.stringify({
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "webhook",
"responseMode": "onReceived",
"options": {}
},
"id": "webhook",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [240, 300]
},
{
"parameters": {
"chatId": "",
"text": "=Новое уведомление: {{$json[\"message\"]}}"
},
"id": "telegram",
"name": "Telegram",
"type": "n8n-nodes-base.telegram",
"typeVersion": 1,
"position": [460, 300]
}
],
"connections": {
"Webhook": {
"main": [[{"node": "Telegram", "type": "main", "index": 0}]]
}
}
}),
required_credentials: JSON.stringify(["telegram_bot_token"]),
difficulty_level: 'beginner',
estimated_setup_time: 15,
is_featured: 1
},
{
name: 'Email в Slack интеграция',
description: 'Пересылка важных писем в канал Slack',
category: 'communication',
template_data: JSON.stringify({
"nodes": [
{
"parameters": {
"pollTimes": {"item": [{"mode": "everyMinute", "value": 5}]}
},
"id": "email",
"name": "Email (IMAP)",
"type": "n8n-nodes-base.emailReadImap",
"typeVersion": 1,
"position": [240, 300]
},
{
"parameters": {
"channel": "#general",
"text": "=Новое письмо от {{$json[\"from\"][\"text\"]}}: {{$json[\"subject\"]}}"
},
"id": "slack",
"name": "Slack",
"type": "n8n-nodes-base.slack",
"typeVersion": 1,
"position": [460, 300]
}
],
"connections": {
"Email (IMAP)": {
"main": [[{"node": "Slack", "type": "main", "index": 0}]]
}
}
}),
required_credentials: JSON.stringify(["imap_credentials", "slack_oauth_token"]),
difficulty_level: 'intermediate',
estimated_setup_time: 25,
is_featured: 1
},
{
name: 'Резервное копирование в Google Drive',
description: 'Автоматическое резервное копирование важных данных в Google Drive',
category: 'backup',
template_data: JSON.stringify({
"nodes": [
{
"parameters": {
"rule": {"interval": [{"field": "hours", "value": 24}]}
},
"id": "schedule",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [240, 300]
},
{
"parameters": {
"operation": "upload",
"fileId": "={{$json[\"file_id\"]}}"
},
"id": "googledrive",
"name": "Google Drive",
"type": "n8n-nodes-base.googleDrive",
"typeVersion": 1,
"position": [460, 300]
}
],
"connections": {
"Schedule Trigger": {
"main": [[{"node": "Google Drive", "type": "main", "index": 0}]]
}
}
}),
required_credentials: JSON.stringify(["google_drive_oauth"]),
difficulty_level: 'intermediate',
estimated_setup_time: 30,
is_featured: 0
},
{
name: 'Автоматизация скоринга лидов',
description: 'Автоматическая оценка и маршрутизация лидов по критериям',
category: 'sales',
template_data: JSON.stringify({
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "lead",
"responseMode": "onReceived"
},
"id": "webhook",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [240, 300]
},
{
"parameters": {
"conditions": {
"number": [{
"value1": "={{$json[\"budget\"]}}",
"operation": "larger",
"value2": 10000
}]
}
},
"id": "if",
"name": "If",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [460, 300]
},
{
"parameters": {
"subject": "Горячий лид!",
"text": "=Высокобюджетный лид: {{$json[\"name\"]}} - Бюджет: ${{$json[\"budget\"]}}"
},
"id": "email",
"name": "Email",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 1,
"position": [680, 200]
}
],
"connections": {
"Webhook": {
"main": [[{"node": "If", "type": "main", "index": 0}]]
},
"If": {
"main": [[{"node": "Email", "type": "main", "index": 0}]]
}
}
}),
required_credentials: JSON.stringify(["smtp_credentials"]),
difficulty_level: 'advanced',
estimated_setup_time: 45,
is_featured: 1
}
];
// Вставляем шаблоны
const templateStmt = db.prepare(`
INSERT OR REPLACE INTO workflow_templates (
name, description, category, template_data, required_credentials,
difficulty_level, estimated_setup_time, is_featured
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`);
templates.forEach(template => {
templateStmt.run([
template.name,
template.description,
template.category,
template.template_data,
template.required_credentials,
template.difficulty_level,
template.estimated_setup_time,
template.is_featured
]);
});
templateStmt.finalize();
// Создание демо пользователя
const bcrypt = require('bcrypt');
const demoPasswordHash = bcrypt.hashSync('demo123', 10);
db.run(`
INSERT OR REPLACE INTO users (id, username, email, password_hash, subscription_type)
VALUES (1, 'demo', 'demo@example.com', ?, 'pro')
`, [demoPasswordHash], function(err) {
if (err) {
console.error('Ошибка создания демо пользователя:', err);
} else {
console.log('✅ Демо пользователь создан: demo@example.com / demo123');
}
callback();
});
}
// Экспорт базы данных и функций
module.exports = {
db,
initDatabase,
DB_PATH
};