@@ -15,6 +15,66 @@ import pool from './config/database';
1515async function runMigrations ( ) {
1616 const client = await pool . connect ( ) ;
1717 try {
18+ // First, ensure base tables exist (for fresh installs without init.sql)
19+ await client . query ( `
20+ -- Users table
21+ CREATE TABLE IF NOT EXISTS users (
22+ id SERIAL PRIMARY KEY,
23+ email VARCHAR(255) UNIQUE NOT NULL,
24+ password_hash VARCHAR(255) NOT NULL,
25+ name VARCHAR(255),
26+ is_admin BOOLEAN DEFAULT false,
27+ telegram_bot_token VARCHAR(255),
28+ telegram_chat_id VARCHAR(255),
29+ discord_webhook_url TEXT,
30+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
31+ );
32+
33+ -- System settings table
34+ CREATE TABLE IF NOT EXISTS system_settings (
35+ key VARCHAR(255) PRIMARY KEY,
36+ value TEXT NOT NULL,
37+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
38+ );
39+
40+ -- Default system settings
41+ INSERT INTO system_settings (key, value) VALUES ('registration_enabled', 'true')
42+ ON CONFLICT (key) DO NOTHING;
43+
44+ -- Products table
45+ CREATE TABLE IF NOT EXISTS products (
46+ id SERIAL PRIMARY KEY,
47+ user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
48+ url TEXT NOT NULL,
49+ name VARCHAR(255),
50+ image_url TEXT,
51+ refresh_interval INTEGER DEFAULT 3600,
52+ last_checked TIMESTAMP,
53+ next_check_at TIMESTAMP,
54+ stock_status VARCHAR(20) DEFAULT 'unknown',
55+ price_drop_threshold DECIMAL(10,2),
56+ target_price DECIMAL(10,2),
57+ notify_back_in_stock BOOLEAN DEFAULT false,
58+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
59+ UNIQUE(user_id, url)
60+ );
61+
62+ -- Price history table
63+ CREATE TABLE IF NOT EXISTS price_history (
64+ id SERIAL PRIMARY KEY,
65+ product_id INTEGER REFERENCES products(id) ON DELETE CASCADE,
66+ price DECIMAL(10,2) NOT NULL,
67+ currency VARCHAR(10) DEFAULT 'USD',
68+ recorded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
69+ );
70+
71+ -- Index for faster price history queries
72+ CREATE INDEX IF NOT EXISTS idx_price_history_product_date
73+ ON price_history(product_id, recorded_at);
74+ ` ) ;
75+
76+ console . log ( 'Base tables ensured' ) ;
77+
1878 // Add AI settings columns to users table if they don't exist
1979 await client . query ( `
2080 DO $$
@@ -90,6 +150,7 @@ async function runMigrations() {
90150 console . log ( 'Database migrations completed' ) ;
91151 } catch ( error ) {
92152 console . error ( 'Migration error:' , error ) ;
153+ throw error ; // Re-throw to prevent server from starting with broken DB
93154 } finally {
94155 client . release ( ) ;
95156 }
@@ -131,17 +192,26 @@ app.use(
131192 }
132193) ;
133194
134- // Start server
135- app . listen ( PORT , async ( ) => {
136- console . log ( `PriceGhost API server running on port ${ PORT } ` ) ;
195+ // Start server with proper initialization sequence
196+ async function startServer ( ) {
197+ try {
198+ // Run database migrations BEFORE accepting connections
199+ await runMigrations ( ) ;
137200
138- // Run database migrations
139- await runMigrations ( ) ;
201+ app . listen ( PORT , ( ) => {
202+ console . log ( `PriceGhost API server running on port ${ PORT } ` ) ;
140203
141- // Start the background price checker
142- if ( process . env . NODE_ENV !== 'test' ) {
143- startScheduler ( ) ;
204+ // Start the background price checker
205+ if ( process . env . NODE_ENV !== 'test' ) {
206+ startScheduler ( ) ;
207+ }
208+ } ) ;
209+ } catch ( error ) {
210+ console . error ( 'Failed to start server:' , error ) ;
211+ process . exit ( 1 ) ;
144212 }
145- } ) ;
213+ }
214+
215+ startServer ( ) ;
146216
147217export default app ;
0 commit comments