new file: .claude/settings.local.json
new file: .gitignore new file: backend/.env.example new file: backend/.gitignore new file: backend/ecosystem.config.js new file: backend/nodemon.json new file: backend/package-lock.json new file: backend/package.json new file: backend/src/config/database.ts new file: backend/src/config/dynamicSwagger.ts new file: backend/src/config/environment.ts new file: backend/src/config/swagger.ts new file: backend/src/controllers/apiKeyController.ts new file: backend/src/controllers/authController.ts new file: backend/src/controllers/databaseController.ts new file: backend/src/controllers/databaseManagementController.ts new file: backend/src/controllers/dynamicApiController.ts new file: backend/src/controllers/endpointController.ts new file: backend/src/controllers/folderController.ts new file: backend/src/controllers/logsController.ts new file: backend/src/controllers/userController.ts new file: backend/src/middleware/apiKey.ts new file: backend/src/middleware/auth.ts new file: backend/src/middleware/logging.ts new file: backend/src/migrations/001_initial_schema.sql new file: backend/src/migrations/002_add_logging.sql new file: backend/src/migrations/003_add_scripting.sql new file: backend/src/migrations/004_add_superadmin.sql new file: backend/src/migrations/run.ts new file: backend/src/migrations/seed.ts new file: backend/src/routes/apiKeys.ts new file: backend/src/routes/auth.ts new file: backend/src/routes/databaseManagement.ts new file: backend/src/routes/databases.ts new file: backend/src/routes/dynamic.ts new file: backend/src/routes/endpoints.ts new file: backend/src/routes/folders.ts new file: backend/src/routes/logs.ts new file: backend/src/routes/users.ts new file: backend/src/server.ts new file: backend/src/services/DatabasePoolManager.ts new file: backend/src/services/ScriptExecutor.ts new file: backend/src/services/SqlExecutor.ts new file: backend/src/types/index.ts new file: backend/tsconfig.json new file: frontend/.gitignore new file: frontend/index.html new file: frontend/nginx.conf new file: frontend/package-lock.json new file: frontend/package.json new file: frontend/postcss.config.js new file: frontend/src/App.tsx new file: frontend/src/components/CodeEditor.tsx
This commit is contained in:
81
backend/src/migrations/001_initial_schema.sql
Normal file
81
backend/src/migrations/001_initial_schema.sql
Normal file
@@ -0,0 +1,81 @@
|
||||
-- Users table
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
username VARCHAR(255) UNIQUE NOT NULL,
|
||||
email VARCHAR(255) UNIQUE NOT NULL,
|
||||
password_hash VARCHAR(255) NOT NULL,
|
||||
role VARCHAR(50) NOT NULL DEFAULT 'user' CHECK (role IN ('admin', 'user')),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Folders table (for organizing endpoints)
|
||||
CREATE TABLE IF NOT EXISTS folders (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(255) NOT NULL,
|
||||
parent_id UUID REFERENCES folders(id) ON DELETE CASCADE,
|
||||
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Databases table (target databases for API endpoints)
|
||||
CREATE TABLE IF NOT EXISTS databases (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(255) NOT NULL UNIQUE,
|
||||
type VARCHAR(50) NOT NULL DEFAULT 'postgresql' CHECK (type IN ('postgresql', 'mysql', 'mssql')),
|
||||
host VARCHAR(255) NOT NULL,
|
||||
port INTEGER NOT NULL,
|
||||
database_name VARCHAR(255) NOT NULL,
|
||||
username VARCHAR(255) NOT NULL,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
ssl BOOLEAN DEFAULT false,
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Endpoints table
|
||||
CREATE TABLE IF NOT EXISTS endpoints (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(255) NOT NULL,
|
||||
description TEXT,
|
||||
method VARCHAR(10) NOT NULL CHECK (method IN ('GET', 'POST', 'PUT', 'DELETE', 'PATCH')),
|
||||
path VARCHAR(500) NOT NULL UNIQUE,
|
||||
database_id UUID REFERENCES databases(id) ON DELETE RESTRICT,
|
||||
sql_query TEXT NOT NULL,
|
||||
parameters JSONB DEFAULT '[]'::jsonb,
|
||||
folder_id UUID REFERENCES folders(id) ON DELETE SET NULL,
|
||||
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
|
||||
is_public BOOLEAN DEFAULT false,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- API Keys table
|
||||
CREATE TABLE IF NOT EXISTS api_keys (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
name VARCHAR(255) NOT NULL,
|
||||
key VARCHAR(500) UNIQUE NOT NULL,
|
||||
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
|
||||
permissions JSONB DEFAULT '[]'::jsonb,
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
expires_at TIMESTAMP
|
||||
);
|
||||
|
||||
-- Indexes for better performance
|
||||
CREATE INDEX IF NOT EXISTS idx_folders_parent_id ON folders(parent_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_folders_user_id ON folders(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_endpoints_folder_id ON endpoints(folder_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_endpoints_user_id ON endpoints(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_endpoints_database_id ON endpoints(database_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_endpoints_path ON endpoints(path);
|
||||
CREATE INDEX IF NOT EXISTS idx_api_keys_key ON api_keys(key);
|
||||
CREATE INDEX IF NOT EXISTS idx_api_keys_user_id ON api_keys(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_databases_name ON databases(name);
|
||||
|
||||
-- Full text search index for endpoints
|
||||
CREATE INDEX IF NOT EXISTS idx_endpoints_search ON endpoints USING gin(
|
||||
to_tsvector('english', name || ' ' || description || ' ' || sql_query)
|
||||
);
|
||||
28
backend/src/migrations/002_add_logging.sql
Normal file
28
backend/src/migrations/002_add_logging.sql
Normal file
@@ -0,0 +1,28 @@
|
||||
-- Add logging fields to endpoints
|
||||
ALTER TABLE endpoints ADD COLUMN IF NOT EXISTS enable_logging BOOLEAN DEFAULT false;
|
||||
|
||||
-- Add logging fields to api_keys
|
||||
ALTER TABLE api_keys ADD COLUMN IF NOT EXISTS enable_logging BOOLEAN DEFAULT false;
|
||||
|
||||
-- Create request_logs table
|
||||
CREATE TABLE IF NOT EXISTS request_logs (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
endpoint_id UUID REFERENCES endpoints(id) ON DELETE CASCADE,
|
||||
api_key_id UUID REFERENCES api_keys(id) ON DELETE SET NULL,
|
||||
method VARCHAR(10) NOT NULL,
|
||||
path VARCHAR(500) NOT NULL,
|
||||
request_params JSONB,
|
||||
request_body JSONB,
|
||||
response_status INTEGER,
|
||||
response_data JSONB,
|
||||
execution_time INTEGER,
|
||||
error_message TEXT,
|
||||
ip_address VARCHAR(45),
|
||||
user_agent TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Create index for faster queries
|
||||
CREATE INDEX IF NOT EXISTS idx_request_logs_endpoint_id ON request_logs(endpoint_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_request_logs_api_key_id ON request_logs(api_key_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_request_logs_created_at ON request_logs(created_at DESC);
|
||||
14
backend/src/migrations/003_add_scripting.sql
Normal file
14
backend/src/migrations/003_add_scripting.sql
Normal file
@@ -0,0 +1,14 @@
|
||||
-- Добавление поддержки скриптинга для эндпоинтов
|
||||
|
||||
-- Добавляем новые колонки для скриптинга
|
||||
ALTER TABLE endpoints
|
||||
ADD COLUMN execution_type VARCHAR(20) DEFAULT 'sql' CHECK (execution_type IN ('sql', 'script')),
|
||||
ADD COLUMN script_language VARCHAR(20) CHECK (script_language IN ('javascript', 'python')),
|
||||
ADD COLUMN script_code TEXT,
|
||||
ADD COLUMN script_queries JSONB DEFAULT '[]'::jsonb;
|
||||
|
||||
-- Комментарии для документации
|
||||
COMMENT ON COLUMN endpoints.execution_type IS 'Тип выполнения: sql - простой SQL запрос, script - скрипт с несколькими запросами';
|
||||
COMMENT ON COLUMN endpoints.script_language IS 'Язык скрипта: javascript или python';
|
||||
COMMENT ON COLUMN endpoints.script_code IS 'Код скрипта (JS или Python)';
|
||||
COMMENT ON COLUMN endpoints.script_queries IS 'Массив именованных SQL запросов для использования в скрипте: [{"name": "queryName", "sql": "SELECT ..."}]';
|
||||
8
backend/src/migrations/004_add_superadmin.sql
Normal file
8
backend/src/migrations/004_add_superadmin.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
-- Add is_superadmin field to users table
|
||||
ALTER TABLE users
|
||||
ADD COLUMN IF NOT EXISTS is_superadmin BOOLEAN DEFAULT FALSE;
|
||||
|
||||
COMMENT ON COLUMN users.is_superadmin IS 'Является ли пользователь супер-администратором с полным доступом';
|
||||
|
||||
ALTER TABLE users
|
||||
DROP COLUMN IF EXISTS email;
|
||||
24
backend/src/migrations/run.ts
Normal file
24
backend/src/migrations/run.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { mainPool } from '../config/database';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
async function runMigrations() {
|
||||
console.log('Running migrations...');
|
||||
|
||||
try {
|
||||
const migrationFile = fs.readFileSync(
|
||||
path.join(__dirname, '001_initial_schema.sql'),
|
||||
'utf-8'
|
||||
);
|
||||
|
||||
await mainPool.query(migrationFile);
|
||||
console.log('✅ Migrations completed successfully');
|
||||
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('❌ Migration failed:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
runMigrations();
|
||||
38
backend/src/migrations/seed.ts
Normal file
38
backend/src/migrations/seed.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { mainPool } from '../config/database';
|
||||
import bcrypt from 'bcrypt';
|
||||
|
||||
async function seed() {
|
||||
console.log('🌱 Starting seed...');
|
||||
|
||||
try {
|
||||
// Проверяем, есть ли уже пользователи
|
||||
const userCheck = await mainPool.query('SELECT COUNT(*) FROM users');
|
||||
const userCount = parseInt(userCheck.rows[0].count);
|
||||
|
||||
if (userCount > 0) {
|
||||
console.log('⚠️ Users already exist. Skipping seed.');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Создаем супер-админа по умолчанию
|
||||
const passwordHash = await bcrypt.hash('admin', 10);
|
||||
|
||||
await mainPool.query(
|
||||
`INSERT INTO users (username, password_hash, role, is_superadmin)
|
||||
VALUES ($1, $2, $3, $4)`,
|
||||
['admin', passwordHash, 'admin', true]
|
||||
);
|
||||
|
||||
console.log('✅ Default superadmin created:');
|
||||
console.log(' Username: admin');
|
||||
console.log(' Password: admin');
|
||||
console.log(' ⚠️ ВАЖНО: Смените пароль после первого входа!');
|
||||
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('❌ Seed failed:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
seed();
|
||||
Reference in New Issue
Block a user