Fix: PostgreSQL setup on production droplet

- Revert schema to pgTable/serial (matches PostgreSQL)
- db.ts switched back to node-postgres driver
- PostgreSQL 16 installed and running on 142.93.245.235
- Database: gammanexus, User: gn_admin
- Same schema across local and production
master
isnowglobal-admin 2026-06-13 19:28:48 -04:00
parent 8763a426e0
commit 1877bb7aa7
2 changed files with 24 additions and 27 deletions

View File

@ -1,35 +1,32 @@
import { drizzle } from "drizzle-orm/better-sqlite3"; import { drizzle } from "drizzle-orm/node-postgres";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { users, User, NewUser } from "../shared/schema"; import { users, User, NewUser } from "../shared/schema";
import Database from "better-sqlite3"; import { Pool } from "pg";
import path from "node:path";
import fs from "node:fs";
import { fileURLToPath } from "node:url";
const __filename = fileURLToPath(import.meta.url); // PostgreSQL connection (local on production droplet)
const __dirname = path.dirname(__filename); const pool = new Pool({
host: process.env.DB_HOST || "127.0.0.1",
port: parseInt(process.env.DB_PORT || "5432"),
user: process.env.DB_USER || "gn_admin",
password: process.env.DB_PASSWORD || "",
database: process.env.DB_NAME || "gammanexus",
ssl: (process.env.DB_SSL === "true" && process.env.NODE_ENV === "production") ? { rejectUnauthorized: false } : false,
max: 20,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 5000,
});
// Use SQLite for production (PostgreSQL migration later) export const db = drizzle(pool);
const dbPath = path.resolve(__dirname, "..", "data.db");
// Ensure data directory exists
const dbDir = path.dirname(dbPath);
if (!fs.existsSync(dbDir)) {
fs.mkdirSync(dbDir, { recursive: true });
}
const sqlite = new Database(dbPath);
export const db = drizzle(sqlite);
// Initialize users table if it doesn't exist (called at startup) // Initialize users table if it doesn't exist (called at startup)
export async function initDb(): Promise<void> { export async function initDb(): Promise<void> {
sqlite.exec(` await db.execute(`
CREATE TABLE IF NOT EXISTS users ( CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT, id SERIAL PRIMARY KEY,
name TEXT NOT NULL, name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE, email TEXT NOT NULL UNIQUE,
password_hash TEXT NOT NULL, password_hash TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
) )
`); `);
} }

View File

@ -1,20 +1,20 @@
// GammaDesk shared data model // GammaDesk shared data model
// ORATS-style options analytics types + Drizzle tables for auth. // ORATS-style options analytics types + Drizzle tables for auth.
// Database: SQLite (PostgreSQL migration planned later) // Database: PostgreSQL
import { z } from "zod"; import { z } from "zod";
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core"; import { pgTable, text, serial, timestamp } from "drizzle-orm/pg-core";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Auth - Users table (Drizzle + SQLite) // Auth - Users table (Drizzle + PostgreSQL)
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
export const users = sqliteTable("users", { export const users = pgTable("users", {
id: integer("id").primaryKey({ autoIncrement: true }), id: serial("id").primaryKey(),
name: text("name").notNull(), name: text("name").notNull(),
email: text("email").notNull().unique(), email: text("email").notNull().unique(),
passwordHash: text("password_hash").notNull(), passwordHash: text("password_hash").notNull(),
createdAt: text("created_at").default(new Date().toISOString()), createdAt: timestamp("created_at", { mode: "date" }).defaultNow().notNull(),
}); });
export type User = typeof users.$inferSelect; export type User = typeof users.$inferSelect;