ccfb674318
continuous-integration/drone/push Build is passing
- Implement Social Features: Shared Tasks, Global Access, Privacy Settings (Leaderboard/Searchable). - Add Leaderboard Page and API. - Enhance Auth: Support Email/Username login, explicit duplicate registration errors. - Fix: Admin login password hash regression. - Refactor: Move to wouter for routing, add Admin Dashboard and User Management. - Add Setup Wizard. - Update UI with Sidebar and Gamification elements.
129 lines
3.6 KiB
TypeScript
129 lines
3.6 KiB
TypeScript
import { drizzle } from 'drizzle-orm/node-postgres';
|
|
import { Pool } from 'pg';
|
|
import { migrate } from 'drizzle-orm/node-postgres/migrator';
|
|
import * as schema from '../shared/schema.js';
|
|
import { sql } from 'drizzle-orm';
|
|
|
|
let db: ReturnType<typeof drizzle> | null = null;
|
|
export let pool: Pool | null = null;
|
|
|
|
export function getDatabase() {
|
|
if (!db) {
|
|
const databaseUrl = process.env.DATABASE_URL;
|
|
|
|
if (!databaseUrl) {
|
|
throw new Error('DATABASE_URL environment variable is not set');
|
|
}
|
|
|
|
// Configure SSL based on DATABASE_SSL environment variable
|
|
// Values: 'true', 'false', or 'require'
|
|
// Default: false (no SSL)
|
|
let sslConfig: any = false;
|
|
|
|
if (process.env.DATABASE_SSL === 'true') {
|
|
sslConfig = { rejectUnauthorized: false }; // SSL with self-signed certs
|
|
} else if (process.env.DATABASE_SSL === 'require') {
|
|
sslConfig = { rejectUnauthorized: true }; // SSL with valid certs only
|
|
}
|
|
// Otherwise defaults to false (no SSL)
|
|
|
|
pool = new Pool({
|
|
connectionString: databaseUrl,
|
|
ssl: sslConfig,
|
|
});
|
|
|
|
db = drizzle(pool, { schema });
|
|
}
|
|
|
|
return db;
|
|
}
|
|
|
|
export async function runMigrations() {
|
|
try {
|
|
const database = getDatabase();
|
|
|
|
// Push schema to database (creates/updates tables as needed)
|
|
// This is equivalent to running `drizzle-kit push`
|
|
console.log('Checking database schema...');
|
|
|
|
// Enable pgcrypto extension for gen_random_uuid()
|
|
await database.execute(sql`CREATE EXTENSION IF NOT EXISTS "pgcrypto"`);
|
|
|
|
// Create tables if they don't exist
|
|
await database.execute(sql`
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id VARCHAR PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
username TEXT NOT NULL UNIQUE,
|
|
password TEXT NOT NULL
|
|
)
|
|
`);
|
|
|
|
await database.execute(sql`
|
|
CREATE TABLE IF NOT EXISTS labels (
|
|
id VARCHAR PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
name TEXT NOT NULL,
|
|
color TEXT NOT NULL
|
|
)
|
|
`);
|
|
|
|
await database.execute(sql`
|
|
CREATE TABLE IF NOT EXISTS tasks (
|
|
id VARCHAR PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
title TEXT NOT NULL,
|
|
description TEXT,
|
|
status TEXT NOT NULL DEFAULT 'todo',
|
|
priority TEXT NOT NULL DEFAULT 'medium',
|
|
due_date TIMESTAMP,
|
|
time_tracked INTEGER NOT NULL DEFAULT 0,
|
|
is_tracking BOOLEAN NOT NULL DEFAULT false,
|
|
project_id TEXT,
|
|
notes TEXT,
|
|
label_id VARCHAR REFERENCES labels(id)
|
|
)
|
|
`);
|
|
|
|
console.log('✓ Database schema is up to date');
|
|
} catch (error) {
|
|
console.error('Failed to run migrations:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export async function initializeDatabase() {
|
|
try {
|
|
// Run migrations first
|
|
await runMigrations();
|
|
|
|
const database = getDatabase();
|
|
|
|
// Create default labels if they don't exist
|
|
const existingLabels = await database.select().from(schema.labels);
|
|
|
|
if (existingLabels.length === 0) {
|
|
const defaultLabels = [
|
|
{ name: "Work", color: "#3B82F6" },
|
|
{ name: "Personal", color: "#10B981" },
|
|
{ name: "Urgent", color: "#EF4444" },
|
|
{ name: "Study", color: "#8B5CF6" },
|
|
];
|
|
|
|
await database.insert(schema.labels).values(defaultLabels);
|
|
console.log('✓ Created default labels');
|
|
}
|
|
|
|
console.log('✓ Database initialized successfully');
|
|
} catch (error) {
|
|
console.error('Failed to initialize database:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
export async function closeDatabase() {
|
|
if (pool) {
|
|
await pool.end();
|
|
pool = null;
|
|
db = null;
|
|
console.log('✓ Database connection closed');
|
|
}
|
|
}
|