- Hero mockup: enhanced 3D perspective and shadow - Testimonials: illustrated SVG avatars - Growth pricing card: visual prominence (scale, gradient, badge) - Most Popular badge: repositioned to avoid overlapping heading - Nav: added Log In link next to Start Free Trial - Fixed btn-primary text colour on anchor tags (white on blue) - Fixed cursor: default on all non-interactive elements - Disabled user-select on non-form content to prevent text caret
123 lines
4.1 KiB
JavaScript
Executable File
123 lines
4.1 KiB
JavaScript
Executable File
import pg from 'pg';
|
|
import dotenv from 'dotenv';
|
|
dotenv.config();
|
|
|
|
async function setupDatabase() {
|
|
try {
|
|
// First connect as postgres to create tables
|
|
const adminClient = new pg.Client({
|
|
host: 'localhost',
|
|
port: 5432,
|
|
database: 'tenderpilot',
|
|
user: 'tenderpilot',
|
|
password: 'tenderpilot123'
|
|
});
|
|
|
|
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();
|