ENTERPRISE: Implement zero-config SSL/TLS with dual HTTP/HTTPS architecture
Major architectural improvements: - Auto-generate SSL certificates on first startup with OpenSSL - Dual HTTP (8081) + HTTPS (8443) backend API servers - Frontend auto-detects protocol and uses appropriate API endpoint - Fix database ORM initialization race condition with getDb() pattern - WebSocket authentication with JWT verification during handshake - Zero-config .env file generation for production deployment - Docker and nginx configurations for container deployment Technical fixes: - Eliminate module initialization race conditions in database access - Replace direct db imports with safer getDb() function calls - Automatic HTTPS frontend development server (npm run dev:https) - SSL certificate generation with termix.crt/termix.key - Cross-platform environment variable support with cross-env This enables seamless HTTP→HTTPS upgrade with zero manual configuration. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -135,6 +135,14 @@ async function initializeCompleteDatabase(): Promise<void> {
|
||||
// Create module-level sqlite instance after database is initialized
|
||||
sqlite = memoryDatabase;
|
||||
|
||||
// Initialize drizzle ORM with the configured database
|
||||
db = drizzle(sqlite, { schema });
|
||||
|
||||
databaseLogger.info("Database ORM initialized", {
|
||||
operation: "drizzle_init",
|
||||
tablesConfigured: Object.keys(schema).length
|
||||
});
|
||||
|
||||
sqlite.exec(`
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
id TEXT PRIMARY KEY,
|
||||
@@ -510,8 +518,19 @@ async function handlePostInitFileEncryption() {
|
||||
}
|
||||
}
|
||||
|
||||
initializeCompleteDatabase()
|
||||
.then(() => handlePostInitFileEncryption())
|
||||
// Export a promise that resolves when database is fully initialized
|
||||
export const databaseReady = initializeCompleteDatabase()
|
||||
.then(async () => {
|
||||
await handlePostInitFileEncryption();
|
||||
|
||||
databaseLogger.success("Database connection established", {
|
||||
operation: "db_init",
|
||||
path: actualDbPath,
|
||||
hasEncryptedBackup:
|
||||
enableFileEncryption &&
|
||||
DatabaseFileEncryption.isEncryptedDatabaseFile(encryptedDbPath),
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
databaseLogger.error("Failed to initialize database", error, {
|
||||
operation: "db_init",
|
||||
@@ -519,14 +538,6 @@ initializeCompleteDatabase()
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
databaseLogger.success("Database connection established", {
|
||||
operation: "db_init",
|
||||
path: actualDbPath,
|
||||
hasEncryptedBackup:
|
||||
enableFileEncryption &&
|
||||
DatabaseFileEncryption.isEncryptedDatabaseFile(encryptedDbPath),
|
||||
});
|
||||
|
||||
// Cleanup function for database and temporary files
|
||||
async function cleanupDatabase() {
|
||||
// Save in-memory database before closing
|
||||
@@ -612,9 +623,19 @@ process.on("SIGTERM", async () => {
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
// Export database connection and file encryption utilities
|
||||
export const db = drizzle(sqlite, { schema });
|
||||
export const sqliteInstance = sqlite; // Export underlying SQLite instance for schema queries
|
||||
// Database connection - will be initialized after database setup
|
||||
let db: ReturnType<typeof drizzle<typeof schema>>;
|
||||
|
||||
// Export database connection getter function to avoid undefined access
|
||||
export function getDb(): ReturnType<typeof drizzle<typeof schema>> {
|
||||
if (!db) {
|
||||
throw new Error("Database not initialized. Ensure databaseReady promise is awaited before accessing db.");
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
// Legacy export for compatibility - will throw if accessed before initialization
|
||||
export { db };
|
||||
export { DatabaseFileEncryption };
|
||||
export const databasePaths = {
|
||||
main: actualDbPath,
|
||||
|
||||
Reference in New Issue
Block a user