import pg from 'pg'; import dotenv from 'dotenv'; dotenv.config(); async function setupDatabase() { try { // Connect using the DATABASE_URL from .env const adminClient = new pg.Client({ connectionString: process.env.DATABASE_URL }); await adminClient.connect(); console.log('Connected to tenderpilot database'); // Create tables await adminClient.query(` CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, email VARCHAR(255) UNIQUE NOT NULL, password_hash VARCHAR(255) NOT NULL, company_name VARCHAR(255), tier VARCHAR(50) DEFAULT 'free', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, verified BOOLEAN DEFAULT false ); `); console.log('Created users table'); await adminClient.query(` CREATE TABLE IF NOT EXISTS tenders ( id SERIAL PRIMARY KEY, source VARCHAR(100) NOT NULL, source_id VARCHAR(255) UNIQUE NOT NULL, title VARCHAR(500) NOT NULL, description TEXT, summary TEXT, cpv_codes TEXT[], value_low DECIMAL(15,2), value_high DECIMAL(15,2), currency VARCHAR(3) DEFAULT 'GBP', published_date TIMESTAMP, deadline TIMESTAMP, authority_name VARCHAR(255), authority_type VARCHAR(100), location VARCHAR(255), documents_url TEXT, notice_url TEXT, status VARCHAR(50) DEFAULT 'open', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); `); console.log('Created tenders table'); await adminClient.query(` CREATE TABLE IF NOT EXISTS profiles ( id SERIAL PRIMARY KEY, user_id INTEGER UNIQUE REFERENCES users(id) ON DELETE CASCADE, sectors TEXT[], keywords TEXT[], min_value DECIMAL(15,2), max_value DECIMAL(15,2), locations TEXT[], authority_types TEXT[], created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); `); console.log('Created profiles table'); await adminClient.query(` CREATE TABLE IF NOT EXISTS matches ( id SERIAL PRIMARY KEY, user_id INTEGER REFERENCES users(id) ON DELETE CASCADE, tender_id INTEGER REFERENCES tenders(id) ON DELETE CASCADE, sent BOOLEAN DEFAULT false, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE(user_id, tender_id) ); `); console.log('Created matches table'); await adminClient.query(` CREATE TABLE IF NOT EXISTS subscriptions ( id SERIAL PRIMARY KEY, user_id INTEGER UNIQUE REFERENCES users(id) ON DELETE CASCADE, stripe_customer_id VARCHAR(255) UNIQUE NOT NULL, stripe_subscription_id VARCHAR(255), plan VARCHAR(50) NOT NULL, status VARCHAR(50) NOT NULL DEFAULT 'active', trial_start TIMESTAMP, trial_end TIMESTAMP, current_period_start TIMESTAMP, current_period_end TIMESTAMP, cancel_at_period_end BOOLEAN DEFAULT false, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); `); console.log('Created subscriptions table'); // Create indexes await adminClient.query('CREATE INDEX IF NOT EXISTS idx_tenders_source_id ON tenders(source_id);'); await adminClient.query('CREATE INDEX IF NOT EXISTS idx_tenders_deadline ON tenders(deadline);'); await adminClient.query('CREATE INDEX IF NOT EXISTS idx_matches_user_id ON matches(user_id);'); await adminClient.query('CREATE INDEX IF NOT EXISTS idx_subscriptions_user_id ON subscriptions(user_id);'); await adminClient.query('CREATE INDEX IF NOT EXISTS idx_subscriptions_stripe_customer_id ON subscriptions(stripe_customer_id);'); console.log('Created indexes'); await adminClient.end(); console.log('Database setup complete!'); } catch (error) { console.error('Error setting up database:', error.message); process.exit(1); } } setupDatabase();