245 lines
7.1 KiB
JavaScript
245 lines
7.1 KiB
JavaScript
/**
|
|
* Database Schema Setup Script
|
|
* Run this script once to create all required tables
|
|
* Usage: npm run db:setup
|
|
*/
|
|
|
|
require('dotenv').config();
|
|
const { pool } = require('./connection');
|
|
|
|
// SQL statements to create tables (matching Developer Guide Part 2)
|
|
const createTablesSQL = `
|
|
-- ============================================
|
|
-- TABLE: users
|
|
-- ============================================
|
|
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),
|
|
phone VARCHAR(20),
|
|
email_verified BOOLEAN DEFAULT FALSE,
|
|
verification_token VARCHAR(255),
|
|
plan VARCHAR(50) DEFAULT 'free',
|
|
plan_started_at TIMESTAMP,
|
|
plan_expires_at TIMESTAMP,
|
|
monthly_quota INTEGER DEFAULT 100,
|
|
calls_this_month INTEGER DEFAULT 0,
|
|
quota_reset_date DATE,
|
|
razorpay_customer_id VARCHAR(100),
|
|
razorpay_subscription_id VARCHAR(100),
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|
updated_at TIMESTAMP DEFAULT NOW(),
|
|
last_login_at TIMESTAMP,
|
|
is_active BOOLEAN DEFAULT TRUE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
|
|
|
|
-- ============================================
|
|
-- TABLE: api_keys
|
|
-- ============================================
|
|
CREATE TABLE IF NOT EXISTS api_keys (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
|
key_prefix VARCHAR(20) NOT NULL,
|
|
key_hash VARCHAR(255) NOT NULL,
|
|
key_hint VARCHAR(10),
|
|
name VARCHAR(100) DEFAULT 'Default',
|
|
is_test_key BOOLEAN DEFAULT FALSE,
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
last_used_at TIMESTAMP,
|
|
total_calls INTEGER DEFAULT 0,
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|
expires_at TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_api_keys_user ON api_keys(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_api_keys_hash ON api_keys(key_hash);
|
|
|
|
-- ============================================
|
|
-- TABLE: api_calls
|
|
-- ============================================
|
|
CREATE TABLE IF NOT EXISTS api_calls (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id INTEGER REFERENCES users(id),
|
|
api_key_id INTEGER REFERENCES api_keys(id),
|
|
endpoint VARCHAR(100) NOT NULL,
|
|
method VARCHAR(10) NOT NULL,
|
|
request_params JSONB,
|
|
response_status INTEGER,
|
|
response_time_ms INTEGER,
|
|
success BOOLEAN,
|
|
error_message VARCHAR(500),
|
|
credits_used INTEGER DEFAULT 1,
|
|
is_billable BOOLEAN DEFAULT TRUE,
|
|
ip_address VARCHAR(45),
|
|
user_agent VARCHAR(500),
|
|
called_at TIMESTAMP DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_api_calls_user ON api_calls(user_id);
|
|
CREATE INDEX IF NOT EXISTS idx_api_calls_date ON api_calls(called_at);
|
|
CREATE INDEX IF NOT EXISTS idx_api_calls_endpoint ON api_calls(endpoint);
|
|
|
|
-- ============================================
|
|
-- TABLE: ifsc_codes
|
|
-- ============================================
|
|
CREATE TABLE IF NOT EXISTS ifsc_codes (
|
|
id SERIAL PRIMARY KEY,
|
|
ifsc VARCHAR(11) UNIQUE NOT NULL,
|
|
bank_name VARCHAR(255) NOT NULL,
|
|
branch VARCHAR(255),
|
|
address TEXT,
|
|
city VARCHAR(100),
|
|
district VARCHAR(100),
|
|
state VARCHAR(100),
|
|
contact VARCHAR(100),
|
|
upi_enabled BOOLEAN DEFAULT FALSE,
|
|
rtgs_enabled BOOLEAN DEFAULT TRUE,
|
|
neft_enabled BOOLEAN DEFAULT TRUE,
|
|
imps_enabled BOOLEAN DEFAULT TRUE,
|
|
micr_code VARCHAR(20),
|
|
swift_code VARCHAR(20),
|
|
updated_at TIMESTAMP DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_ifsc ON ifsc_codes(ifsc);
|
|
|
|
-- ============================================
|
|
-- TABLE: pincodes
|
|
-- ============================================
|
|
CREATE TABLE IF NOT EXISTS pincodes (
|
|
id SERIAL PRIMARY KEY,
|
|
pincode VARCHAR(6) NOT NULL,
|
|
office_name VARCHAR(255),
|
|
office_type VARCHAR(50),
|
|
district VARCHAR(100),
|
|
division VARCHAR(100),
|
|
region VARCHAR(100),
|
|
state VARCHAR(100),
|
|
latitude DECIMAL(10, 8),
|
|
longitude DECIMAL(11, 8),
|
|
updated_at TIMESTAMP DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_pincode ON pincodes(pincode);
|
|
|
|
-- ============================================
|
|
-- TABLE: pan_data
|
|
-- ============================================
|
|
CREATE TABLE IF NOT EXISTS pan_data (
|
|
pan_number VARCHAR(10) PRIMARY KEY,
|
|
full_name VARCHAR(255),
|
|
father_name VARCHAR(255),
|
|
date_of_birth DATE,
|
|
gender VARCHAR(10),
|
|
category VARCHAR(50),
|
|
status VARCHAR(50),
|
|
updated_at TIMESTAMP DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_pan_number ON pan_data(pan_number);
|
|
|
|
-- ============================================
|
|
-- TABLE: subscriptions
|
|
-- ============================================
|
|
CREATE TABLE IF NOT EXISTS subscriptions (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id INTEGER REFERENCES users(id),
|
|
razorpay_subscription_id VARCHAR(100),
|
|
razorpay_payment_id VARCHAR(100),
|
|
razorpay_plan_id VARCHAR(100),
|
|
plan_name VARCHAR(50),
|
|
amount DECIMAL(10, 2),
|
|
currency VARCHAR(3) DEFAULT 'INR',
|
|
status VARCHAR(50),
|
|
current_period_start TIMESTAMP,
|
|
current_period_end TIMESTAMP,
|
|
created_at TIMESTAMP DEFAULT NOW(),
|
|
cancelled_at TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_subscriptions_user ON subscriptions(user_id);
|
|
|
|
-- ============================================
|
|
-- TABLE: invoices
|
|
-- ============================================
|
|
CREATE TABLE IF NOT EXISTS invoices (
|
|
id SERIAL PRIMARY KEY,
|
|
user_id INTEGER REFERENCES users(id),
|
|
subscription_id INTEGER REFERENCES subscriptions(id),
|
|
invoice_number VARCHAR(50) UNIQUE,
|
|
amount DECIMAL(10, 2),
|
|
tax_amount DECIMAL(10, 2),
|
|
total_amount DECIMAL(10, 2),
|
|
currency VARCHAR(3) DEFAULT 'INR',
|
|
status VARCHAR(50),
|
|
razorpay_invoice_id VARCHAR(100),
|
|
razorpay_payment_id VARCHAR(100),
|
|
invoice_date DATE,
|
|
due_date DATE,
|
|
paid_at TIMESTAMP,
|
|
pdf_url VARCHAR(500),
|
|
created_at TIMESTAMP DEFAULT NOW()
|
|
);
|
|
`;
|
|
|
|
/**
|
|
* Run database setup
|
|
*/
|
|
const setupDatabase = async () => {
|
|
console.log('🚀 Starting database setup...\n');
|
|
|
|
const client = await pool.connect();
|
|
|
|
try {
|
|
// Start transaction
|
|
await client.query('BEGIN');
|
|
|
|
// Create tables
|
|
console.log('📦 Creating tables...');
|
|
await client.query(createTablesSQL);
|
|
console.log('✅ Tables created successfully\n');
|
|
|
|
// Commit transaction
|
|
await client.query('COMMIT');
|
|
|
|
// Display created tables
|
|
const tablesResult = await client.query(`
|
|
SELECT table_name
|
|
FROM information_schema.tables
|
|
WHERE table_schema = 'public'
|
|
AND table_type = 'BASE TABLE'
|
|
ORDER BY table_name;
|
|
`);
|
|
|
|
console.log('📋 Created tables:');
|
|
tablesResult.rows.forEach((row, index) => {
|
|
console.log(` ${index + 1}. ${row.table_name}`);
|
|
});
|
|
|
|
console.log('\n✅ Database setup completed successfully!');
|
|
|
|
} catch (error) {
|
|
// Rollback on error
|
|
await client.query('ROLLBACK');
|
|
console.error('\n❌ Database setup failed:', error.message);
|
|
console.error('🔄 Transaction rolled back');
|
|
throw error;
|
|
} finally {
|
|
client.release();
|
|
}
|
|
};
|
|
|
|
// Run setup
|
|
setupDatabase()
|
|
.then(() => {
|
|
console.log('\n👋 Exiting...');
|
|
process.exit(0);
|
|
})
|
|
.catch((error) => {
|
|
console.error('\n💥 Fatal error:', error);
|
|
process.exit(1);
|
|
});
|