@vezlo/assistant-server 1.0.0 → 1.1.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/README.md CHANGED
@@ -32,63 +32,110 @@ cd assistant-server
32
32
  npm install
33
33
  ```
34
34
 
35
- ## šŸš€ Quick Start
35
+ ## šŸš€ Quick Start (Interactive Setup)
36
36
 
37
37
  ### Prerequisites
38
38
  - Node.js 20+ and npm 9+
39
- - Supabase project with vector extension
39
+ - Supabase project (or PostgreSQL database)
40
40
  - OpenAI API key
41
41
 
42
- ### 1. Setup Environment
42
+ ### Easy Setup with Interactive Wizard
43
+
44
+ The fastest way to get started is with our interactive setup wizard:
43
45
 
44
46
  ```bash
45
- # If installed via npm, create a project directory
46
- mkdir my-ai-assistant
47
- cd my-ai-assistant
47
+ # If installed globally
48
+ vezlo-setup
48
49
 
49
- # Copy example environment file
50
- cp node_modules/@vezlo/assistant-server/env.example .env
50
+ # If installed locally
51
+ npx vezlo-setup
51
52
 
52
53
  # Or if cloned from GitHub
54
+ npm run setup
55
+ ```
56
+
57
+ The wizard will guide you through:
58
+ 1. **Database Configuration** - Choose Supabase or PostgreSQL
59
+ 2. **OpenAI API Setup** - Configure your AI model
60
+ 3. **Automatic Table Creation** - Creates all required database tables
61
+ 4. **Environment File Generation** - Saves configuration to .env
62
+
63
+ After setup completes, start the server:
64
+
65
+ ```bash
66
+ vezlo-server
67
+ ```
68
+
69
+ ### Manual Setup (Advanced)
70
+
71
+ If you prefer manual configuration:
72
+
73
+ #### 1. Create Environment File
74
+
75
+ ```bash
76
+ # Copy example file
53
77
  cp env.example .env
54
78
 
55
- # Edit .env with your credentials (see Environment Configuration below)
79
+ # Edit with your credentials
80
+ nano .env
56
81
  ```
57
82
 
58
- ### 2. Setup Database
83
+ #### 2. Configure Database
84
+
85
+ Get your Supabase credentials from:
86
+ - **Dashboard** → Settings → API
87
+ - **Database** → Settings → Connection string
59
88
 
60
- Run the database schema in your Supabase SQL Editor:
89
+ ```env
90
+ # Supabase Configuration
91
+ SUPABASE_URL=https://your-project.supabase.co
92
+ SUPABASE_SERVICE_KEY=your-service-role-key
93
+ SUPABASE_DB_HOST=db.your-project.supabase.co
94
+ SUPABASE_DB_PASSWORD=your-database-password
95
+
96
+ # OpenAI Configuration
97
+ OPENAI_API_KEY=sk-your-api-key
98
+ ```
99
+
100
+ #### 3. Setup Database Tables
101
+
102
+ **Option A: Automated Setup**
61
103
  ```bash
62
- # Copy from package installation
63
- cat node_modules/@vezlo/assistant-server/database-schema.sql
104
+ vezlo-setup # Run wizard and choose option 3 to use existing .env
105
+ ```
64
106
 
65
- # Or from cloned repo
107
+ **Option B: Manual SQL**
108
+ ```bash
109
+ # Copy schema to Supabase SQL Editor
66
110
  cat database-schema.sql
111
+
112
+ # Then execute in Supabase Dashboard → SQL Editor
67
113
  ```
68
114
 
69
- ### 3. Start the Server
115
+ #### 4. Validate Setup
116
+
117
+ ```bash
118
+ # Verify database connection and tables
119
+ vezlo-validate
120
+
121
+ # Or with npm
122
+ npm run validate
123
+ ```
124
+
125
+ #### 5. Start Server
70
126
 
71
127
  ```bash
72
128
  # If installed globally
73
129
  vezlo-server
74
130
 
75
- # If installed locally in project
131
+ # If installed locally
76
132
  npx vezlo-server
77
133
 
78
- # Or if cloned from GitHub
134
+ # Or from source
79
135
  npm run build && npm start
80
136
  ```
81
137
 
82
- ### 4. Verify Installation
83
- ```bash
84
- # Health check
85
- curl http://localhost:3000/health
86
-
87
- # API documentation
88
- open http://localhost:3000/docs
89
- ```
90
-
91
- ### 5. Docker Deployment (Optional)
138
+ ### Docker Deployment
92
139
 
93
140
  ```bash
94
141
  # Start with Docker Compose
@@ -135,6 +182,28 @@ CHUNK_SIZE=1000
135
182
  CHUNK_OVERLAP=200
136
183
  ```
137
184
 
185
+ ## šŸ”§ CLI Commands
186
+
187
+ The package provides these command-line tools:
188
+
189
+ ### vezlo-setup
190
+ Interactive wizard for initial configuration and database setup.
191
+ ```bash
192
+ vezlo-setup
193
+ ```
194
+
195
+ ### vezlo-validate
196
+ Validates database connection and verifies all tables exist.
197
+ ```bash
198
+ vezlo-validate
199
+ ```
200
+
201
+ ### vezlo-server
202
+ Starts the API server.
203
+ ```bash
204
+ vezlo-server
205
+ ```
206
+
138
207
  ## šŸ“š API Documentation
139
208
 
140
209
  ### Base URL
package/package.json CHANGED
@@ -1,15 +1,18 @@
1
1
  {
2
2
  "name": "@vezlo/assistant-server",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Production-ready AI Assistant Server with vector search, conversation management, and real-time communication",
5
5
  "main": "dist/server.js",
6
6
  "types": "dist/server.d.ts",
7
7
  "bin": {
8
- "vezlo-server": "./bin/vezlo-server.js"
8
+ "vezlo-server": "./bin/vezlo-server.js",
9
+ "vezlo-setup": "./scripts/setup.js",
10
+ "vezlo-validate": "./scripts/validate-db.js"
9
11
  },
10
12
  "files": [
11
13
  "dist/",
12
14
  "bin/",
15
+ "scripts/",
13
16
  "database-schema.sql",
14
17
  "knexfile.ts",
15
18
  "env.example",
@@ -22,6 +25,8 @@
22
25
  "build": "tsc",
23
26
  "start": "node dist/server.js",
24
27
  "prepublishOnly": "npm run build",
28
+ "setup": "node scripts/setup.js",
29
+ "validate": "node scripts/validate-db.js",
25
30
  "migrate:make": "knex migrate:make",
26
31
  "migrate:latest": "knex migrate:latest",
27
32
  "migrate:rollback": "knex migrate:rollback",
@@ -0,0 +1,21 @@
1
+ #!/bin/sh
2
+
3
+ # Migration runner script for Docker
4
+ # This script runs database migrations before starting the application
5
+
6
+ set -e
7
+
8
+ echo "Starting Vezlo Server with Database Migrations..."
9
+
10
+ # Wait for database to be ready (optional)
11
+ echo "Waiting for database connection..."
12
+ sleep 2
13
+
14
+ # Run migrations
15
+ echo "Running database migrations..."
16
+ npm run migrate:latest
17
+
18
+ # Start the application
19
+ echo "Starting Vezlo Server..."
20
+ exec "$@"
21
+
@@ -0,0 +1,339 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Vezlo Assistant Server Setup Wizard
5
+ * Interactive CLI to configure database and environment
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const readline = require('readline');
11
+ const { createClient } = require('@supabase/supabase-js');
12
+
13
+ const rl = readline.createInterface({
14
+ input: process.stdin,
15
+ output: process.stdout
16
+ });
17
+
18
+ // ANSI color codes
19
+ const colors = {
20
+ reset: '\x1b[0m',
21
+ bright: '\x1b[1m',
22
+ green: '\x1b[32m',
23
+ yellow: '\x1b[33m',
24
+ blue: '\x1b[34m',
25
+ red: '\x1b[31m',
26
+ cyan: '\x1b[36m'
27
+ };
28
+
29
+ function log(message, color = 'reset') {
30
+ console.log(`${colors[color]}${message}${colors.reset}`);
31
+ }
32
+
33
+ function question(prompt) {
34
+ return new Promise(resolve => {
35
+ rl.question(`${colors.cyan}${prompt}${colors.reset} `, resolve);
36
+ });
37
+ }
38
+
39
+ async function main() {
40
+ console.clear();
41
+ log('\nšŸš€ Vezlo Assistant Server Setup Wizard\n', 'bright');
42
+ log('This wizard will help you configure your server in 3 easy steps:\n', 'blue');
43
+ log(' 1. Database Connection (Supabase or PostgreSQL)');
44
+ log(' 2. OpenAI API Configuration');
45
+ log(' 3. Automatic Table Creation\n');
46
+
47
+ // Step 1: Database Type Selection
48
+ log('\n═══════════════════════════════════════════════════════════', 'cyan');
49
+ log(' STEP 1: Database Configuration', 'bright');
50
+ log('═══════════════════════════════════════════════════════════\n', 'cyan');
51
+
52
+ log('Choose your database type:');
53
+ log(' [1] Supabase (Recommended)');
54
+ log(' [2] PostgreSQL (Direct Connection)');
55
+ log(' [3] Use existing .env file\n');
56
+
57
+ const dbChoice = await question('Enter your choice (1-3):');
58
+
59
+ let config = {};
60
+
61
+ if (dbChoice === '1') {
62
+ config = await setupSupabase();
63
+ } else if (dbChoice === '2') {
64
+ config = await setupPostgreSQL();
65
+ } else if (dbChoice === '3') {
66
+ config = await loadExistingConfig();
67
+ } else {
68
+ log('\nāŒ Invalid choice. Exiting...', 'red');
69
+ rl.close();
70
+ return;
71
+ }
72
+
73
+ // Step 2: OpenAI Configuration
74
+ log('\n═══════════════════════════════════════════════════════════', 'cyan');
75
+ log(' STEP 2: OpenAI API Configuration', 'bright');
76
+ log('═══════════════════════════════════════════════════════════\n', 'cyan');
77
+
78
+ const openaiKey = await question('Enter your OpenAI API key (sk-...):');
79
+ config.OPENAI_API_KEY = openaiKey.trim();
80
+
81
+ const aiModel = await question('AI Model (default: gpt-4o):') || 'gpt-4o';
82
+ config.AI_MODEL = aiModel.trim();
83
+
84
+ // Step 3: Save Configuration
85
+ log('\n═══════════════════════════════════════════════════════════', 'cyan');
86
+ log(' STEP 3: Save Configuration', 'bright');
87
+ log('═══════════════════════════════════════════════════════════\n', 'cyan');
88
+
89
+ const envPath = path.join(process.cwd(), '.env');
90
+ await saveEnvFile(envPath, config);
91
+
92
+ log('\nāœ… Configuration saved to .env', 'green');
93
+
94
+ // Step 4: Database Setup
95
+ log('\n═══════════════════════════════════════════════════════════', 'cyan');
96
+ log(' STEP 4: Database Setup', 'bright');
97
+ log('═══════════════════════════════════════════════════════════\n', 'cyan');
98
+
99
+ const setupDb = await question('Setup database tables now? (y/n):');
100
+
101
+ if (setupDb.toLowerCase() === 'y') {
102
+ await setupDatabase(config);
103
+ } else {
104
+ log('\nāš ļø Skipping database setup.', 'yellow');
105
+ log(' Run "npx vezlo-setup-db" later to create tables.\n', 'yellow');
106
+ }
107
+
108
+ // Final Instructions
109
+ log('\n═══════════════════════════════════════════════════════════', 'green');
110
+ log(' šŸŽ‰ Setup Complete!', 'bright');
111
+ log('═══════════════════════════════════════════════════════════\n', 'green');
112
+
113
+ log('Next steps:');
114
+ log(' 1. Review your .env file');
115
+ log(' 2. Start the server: ' + colors.bright + 'vezlo-server' + colors.reset);
116
+ log(' 3. Visit: ' + colors.bright + 'http://localhost:3000/health' + colors.reset);
117
+ log(' 4. API docs: ' + colors.bright + 'http://localhost:3000/docs' + colors.reset + '\n');
118
+
119
+ rl.close();
120
+ }
121
+
122
+ async function setupSupabase() {
123
+ log('\nšŸ“¦ Supabase Configuration\n', 'blue');
124
+ log('You can find these values in your Supabase Dashboard:', 'yellow');
125
+ log(' Settings > API > Project URL & API Keys\n', 'yellow');
126
+
127
+ const supabaseUrl = await question('Supabase Project URL (https://xxx.supabase.co):');
128
+ const supabaseAnonKey = await question('Supabase Anon Key:');
129
+ const supabaseServiceKey = await question('Supabase Service Role Key:');
130
+
131
+ // Validate connection
132
+ log('\nšŸ”„ Testing connection...', 'yellow');
133
+
134
+ try {
135
+ const client = createClient(supabaseUrl.trim(), supabaseServiceKey.trim());
136
+ const { data, error } = await client.from('_test').select('*').limit(1);
137
+
138
+ // This will fail but confirms we can connect
139
+ if (error && error.code !== 'PGRST204' && error.code !== '42P01') {
140
+ log(`\nāš ļø Warning: ${error.message}`, 'yellow');
141
+ log('Continuing with setup...\n', 'yellow');
142
+ } else {
143
+ log('āœ… Connection successful!\n', 'green');
144
+ }
145
+ } catch (err) {
146
+ log(`\nāš ļø Warning: Could not verify connection`, 'yellow');
147
+ log('Continuing with setup...\n', 'yellow');
148
+ }
149
+
150
+ // Extract database connection info from Supabase URL
151
+ const projectId = supabaseUrl.match(/https:\/\/(.+?)\.supabase\.co/)?.[1];
152
+ const dbHost = projectId ? `db.${projectId}.supabase.co` : '';
153
+
154
+ log('Database connection details:', 'blue');
155
+ log(` Host: ${dbHost}`);
156
+ log(` Port: 5432`);
157
+ log(` Database: postgres`);
158
+ log(` User: postgres\n`);
159
+
160
+ const dbPassword = await question('Supabase Database Password (from Settings > Database):');
161
+
162
+ return {
163
+ SUPABASE_URL: supabaseUrl.trim(),
164
+ SUPABASE_ANON_KEY: supabaseAnonKey.trim(),
165
+ SUPABASE_SERVICE_KEY: supabaseServiceKey.trim(),
166
+ SUPABASE_DB_HOST: dbHost,
167
+ SUPABASE_DB_PORT: '5432',
168
+ SUPABASE_DB_NAME: 'postgres',
169
+ SUPABASE_DB_USER: 'postgres',
170
+ SUPABASE_DB_PASSWORD: dbPassword.trim(),
171
+ PORT: '3000',
172
+ NODE_ENV: 'development',
173
+ CORS_ORIGINS: 'http://localhost:3000,http://localhost:5173'
174
+ };
175
+ }
176
+
177
+ async function setupPostgreSQL() {
178
+ log('\nšŸ—„ļø PostgreSQL Configuration\n', 'blue');
179
+
180
+ const host = await question('Database Host (localhost):') || 'localhost';
181
+ const port = await question('Database Port (5432):') || '5432';
182
+ const database = await question('Database Name (postgres):') || 'postgres';
183
+ const user = await question('Database User (postgres):') || 'postgres';
184
+ const password = await question('Database Password:');
185
+
186
+ return {
187
+ SUPABASE_DB_HOST: host.trim(),
188
+ SUPABASE_DB_PORT: port.trim(),
189
+ SUPABASE_DB_NAME: database.trim(),
190
+ SUPABASE_DB_USER: user.trim(),
191
+ SUPABASE_DB_PASSWORD: password.trim(),
192
+ PORT: '3000',
193
+ NODE_ENV: 'development',
194
+ CORS_ORIGINS: 'http://localhost:3000,http://localhost:5173'
195
+ };
196
+ }
197
+
198
+ async function loadExistingConfig() {
199
+ const envPath = path.join(process.cwd(), '.env');
200
+
201
+ if (!fs.existsSync(envPath)) {
202
+ log('\nāŒ No .env file found in current directory', 'red');
203
+ throw new Error('.env file not found');
204
+ }
205
+
206
+ log('\nāœ… Loading configuration from .env\n', 'green');
207
+
208
+ const envContent = fs.readFileSync(envPath, 'utf8');
209
+ const config = {};
210
+
211
+ envContent.split('\n').forEach(line => {
212
+ const match = line.match(/^([^=:#]+)=(.*)$/);
213
+ if (match) {
214
+ const key = match[1].trim();
215
+ const value = match[2].trim();
216
+ config[key] = value;
217
+ }
218
+ });
219
+
220
+ return config;
221
+ }
222
+
223
+ async function saveEnvFile(envPath, config) {
224
+ const envContent = `# Vezlo Assistant Server Configuration
225
+ # Generated by setup wizard on ${new Date().toISOString()}
226
+
227
+ # Server Configuration
228
+ PORT=${config.PORT || '3000'}
229
+ NODE_ENV=${config.NODE_ENV || 'development'}
230
+ LOG_LEVEL=info
231
+
232
+ # CORS Configuration
233
+ CORS_ORIGINS=${config.CORS_ORIGINS || 'http://localhost:3000,http://localhost:5173'}
234
+
235
+ # Rate Limiting
236
+ RATE_LIMIT_WINDOW=60000
237
+ RATE_LIMIT_MAX=100
238
+
239
+ # Supabase Configuration
240
+ ${config.SUPABASE_URL ? `SUPABASE_URL=${config.SUPABASE_URL}` : '# SUPABASE_URL=https://your-project.supabase.co'}
241
+ ${config.SUPABASE_ANON_KEY ? `SUPABASE_ANON_KEY=${config.SUPABASE_ANON_KEY}` : '# SUPABASE_ANON_KEY=your-anon-key'}
242
+ ${config.SUPABASE_SERVICE_KEY ? `SUPABASE_SERVICE_KEY=${config.SUPABASE_SERVICE_KEY}` : '# SUPABASE_SERVICE_KEY=your-service-role-key'}
243
+
244
+ # Database Configuration
245
+ SUPABASE_DB_HOST=${config.SUPABASE_DB_HOST || 'localhost'}
246
+ SUPABASE_DB_PORT=${config.SUPABASE_DB_PORT || '5432'}
247
+ SUPABASE_DB_NAME=${config.SUPABASE_DB_NAME || 'postgres'}
248
+ SUPABASE_DB_USER=${config.SUPABASE_DB_USER || 'postgres'}
249
+ SUPABASE_DB_PASSWORD=${config.SUPABASE_DB_PASSWORD || ''}
250
+
251
+ # OpenAI Configuration
252
+ OPENAI_API_KEY=${config.OPENAI_API_KEY || 'sk-your-openai-api-key'}
253
+ AI_MODEL=${config.AI_MODEL || 'gpt-4o'}
254
+ AI_TEMPERATURE=0.7
255
+ AI_MAX_TOKENS=1000
256
+
257
+ # Organization Settings
258
+ ORGANIZATION_NAME=Vezlo
259
+ ASSISTANT_NAME=Vezlo Assistant
260
+
261
+ # Knowledge Base
262
+ CHUNK_SIZE=1000
263
+ CHUNK_OVERLAP=200
264
+ `;
265
+
266
+ fs.writeFileSync(envPath, envContent, 'utf8');
267
+ }
268
+
269
+ async function setupDatabase(config) {
270
+ log('\nšŸ”„ Setting up database tables...', 'yellow');
271
+
272
+ try {
273
+ const { Client } = require('pg');
274
+
275
+ const client = new Client({
276
+ host: config.SUPABASE_DB_HOST,
277
+ port: parseInt(config.SUPABASE_DB_PORT || '5432'),
278
+ database: config.SUPABASE_DB_NAME,
279
+ user: config.SUPABASE_DB_USER,
280
+ password: config.SUPABASE_DB_PASSWORD,
281
+ ssl: { rejectUnauthorized: false }
282
+ });
283
+
284
+ await client.connect();
285
+ log('āœ… Connected to database', 'green');
286
+
287
+ // Read schema file
288
+ const schemaPath = path.join(__dirname, '..', 'database-schema.sql');
289
+
290
+ if (!fs.existsSync(schemaPath)) {
291
+ log('āŒ database-schema.sql not found', 'red');
292
+ return;
293
+ }
294
+
295
+ const schema = fs.readFileSync(schemaPath, 'utf8');
296
+
297
+ log('šŸ”„ Creating tables...', 'yellow');
298
+ await client.query(schema);
299
+
300
+ log('āœ… Database tables created successfully!', 'green');
301
+
302
+ // Verify tables
303
+ const result = await client.query(`
304
+ SELECT table_name
305
+ FROM information_schema.tables
306
+ WHERE table_schema = 'public'
307
+ AND table_name IN ('conversations', 'messages', 'message_feedback', 'knowledge_items')
308
+ ORDER BY table_name
309
+ `);
310
+
311
+ log('\nšŸ“Š Verified tables:', 'blue');
312
+ result.rows.forEach(row => {
313
+ log(` āœ“ ${row.table_name}`, 'green');
314
+ });
315
+ log('');
316
+
317
+ await client.end();
318
+
319
+ } catch (error) {
320
+ log(`\nāŒ Database setup failed: ${error.message}`, 'red');
321
+ log('\nYou can manually run the setup later:', 'yellow');
322
+ log(' 1. Copy database-schema.sql to your Supabase SQL Editor', 'yellow');
323
+ log(' 2. Execute the SQL to create tables\n', 'yellow');
324
+ }
325
+ }
326
+
327
+ // Handle errors and cleanup
328
+ process.on('SIGINT', () => {
329
+ log('\n\nāš ļø Setup cancelled by user', 'yellow');
330
+ rl.close();
331
+ process.exit(0);
332
+ });
333
+
334
+ // Run the wizard
335
+ main().catch(error => {
336
+ log(`\nāŒ Setup failed: ${error.message}`, 'red');
337
+ rl.close();
338
+ process.exit(1);
339
+ });
@@ -0,0 +1,171 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Vezlo Assistant Server - Database Validation
5
+ * Validates database connection and table setup
6
+ */
7
+
8
+ const dotenv = require('dotenv');
9
+ const { createClient } = require('@supabase/supabase-js');
10
+
11
+ // Load environment variables
12
+ dotenv.config();
13
+
14
+ const colors = {
15
+ reset: '\x1b[0m',
16
+ green: '\x1b[32m',
17
+ yellow: '\x1b[33m',
18
+ red: '\x1b[31m',
19
+ cyan: '\x1b[36m',
20
+ bright: '\x1b[1m'
21
+ };
22
+
23
+ function log(message, color = 'reset') {
24
+ console.log(`${colors[color]}${message}${colors.reset}`);
25
+ }
26
+
27
+ async function validateDatabase() {
28
+ log('\nšŸ” Validating Database Configuration\n', 'cyan');
29
+
30
+ // Check environment variables
31
+ log('Checking environment variables...', 'yellow');
32
+
33
+ const requiredVars = [
34
+ 'SUPABASE_URL',
35
+ 'SUPABASE_SERVICE_KEY',
36
+ 'SUPABASE_DB_HOST',
37
+ 'SUPABASE_DB_PASSWORD'
38
+ ];
39
+
40
+ const missing = requiredVars.filter(key => !process.env[key]);
41
+
42
+ if (missing.length > 0) {
43
+ log(`\nāŒ Missing required environment variables:`, 'red');
44
+ missing.forEach(key => log(` - ${key}`, 'red'));
45
+ log('\nRun the setup wizard: ' + colors.bright + 'npx vezlo-setup' + colors.reset + '\n', 'yellow');
46
+ process.exit(1);
47
+ }
48
+
49
+ log('āœ… Environment variables configured\n', 'green');
50
+
51
+ // Test Supabase connection
52
+ log('Testing Supabase connection...', 'yellow');
53
+
54
+ try {
55
+ const supabase = createClient(
56
+ process.env.SUPABASE_URL,
57
+ process.env.SUPABASE_SERVICE_KEY
58
+ );
59
+
60
+ // Try to query a table
61
+ const { error } = await supabase.from('conversations').select('count').limit(0);
62
+
63
+ if (error && error.code !== 'PGRST116') {
64
+ throw error;
65
+ }
66
+
67
+ log('āœ… Supabase connection successful\n', 'green');
68
+
69
+ } catch (error) {
70
+ log(`āŒ Supabase connection failed: ${error.message}\n`, 'red');
71
+ process.exit(1);
72
+ }
73
+
74
+ // Test database connection and validate tables
75
+ log('Validating database tables...', 'yellow');
76
+
77
+ try {
78
+ const { Client } = require('pg');
79
+
80
+ const client = new Client({
81
+ host: process.env.SUPABASE_DB_HOST,
82
+ port: parseInt(process.env.SUPABASE_DB_PORT || '5432'),
83
+ database: process.env.SUPABASE_DB_NAME || 'postgres',
84
+ user: process.env.SUPABASE_DB_USER || 'postgres',
85
+ password: process.env.SUPABASE_DB_PASSWORD,
86
+ ssl: { rejectUnauthorized: false }
87
+ });
88
+
89
+ await client.connect();
90
+
91
+ // Check required tables
92
+ const requiredTables = [
93
+ 'conversations',
94
+ 'messages',
95
+ 'message_feedback',
96
+ 'knowledge_items'
97
+ ];
98
+
99
+ const result = await client.query(`
100
+ SELECT table_name
101
+ FROM information_schema.tables
102
+ WHERE table_schema = 'public'
103
+ AND table_name = ANY($1)
104
+ ORDER BY table_name
105
+ `, [requiredTables]);
106
+
107
+ const existingTables = result.rows.map(row => row.table_name);
108
+ const missingTables = requiredTables.filter(t => !existingTables.includes(t));
109
+
110
+ if (missingTables.length > 0) {
111
+ log(`\nāŒ Missing required tables:`, 'red');
112
+ missingTables.forEach(table => log(` - ${table}`, 'red'));
113
+ log('\nRun the setup wizard: ' + colors.bright + 'npx vezlo-setup' + colors.reset + '\n', 'yellow');
114
+ await client.end();
115
+ process.exit(1);
116
+ }
117
+
118
+ log('āœ… All required tables exist\n', 'green');
119
+
120
+ // Check table structure
121
+ log('Checking table structure...', 'yellow');
122
+
123
+ const schemaCheck = await client.query(`
124
+ SELECT
125
+ t.table_name,
126
+ COUNT(c.column_name) as column_count
127
+ FROM information_schema.tables t
128
+ LEFT JOIN information_schema.columns c
129
+ ON c.table_name = t.table_name
130
+ AND c.table_schema = t.table_schema
131
+ WHERE t.table_schema = 'public'
132
+ AND t.table_name = ANY($1)
133
+ GROUP BY t.table_name
134
+ ORDER BY t.table_name
135
+ `, [requiredTables]);
136
+
137
+ log('\nšŸ“Š Table Structure:', 'cyan');
138
+ schemaCheck.rows.forEach(row => {
139
+ log(` āœ“ ${row.table_name} (${row.column_count} columns)`, 'green');
140
+ });
141
+
142
+ // Check for vector extension
143
+ const vectorCheck = await client.query(`
144
+ SELECT EXISTS(
145
+ SELECT 1 FROM pg_extension WHERE extname = 'vector'
146
+ ) as has_vector
147
+ `);
148
+
149
+ if (vectorCheck.rows[0].has_vector) {
150
+ log(' āœ“ pgvector extension enabled', 'green');
151
+ } else {
152
+ log(' āš ļø pgvector extension not enabled (semantic search disabled)', 'yellow');
153
+ }
154
+
155
+ log('\nāœ… Database validation complete!\n', 'green');
156
+ log('Your server is ready to start:', 'cyan');
157
+ log(' ' + colors.bright + 'vezlo-server' + colors.reset + '\n');
158
+
159
+ await client.end();
160
+
161
+ } catch (error) {
162
+ log(`\nāŒ Database validation failed: ${error.message}\n`, 'red');
163
+ process.exit(1);
164
+ }
165
+ }
166
+
167
+ // Run validation
168
+ validateDatabase().catch(error => {
169
+ log(`\nāŒ Validation failed: ${error.message}\n`, 'red');
170
+ process.exit(1);
171
+ });