task-manager-pro / db_manager.js
kirimdata369's picture
Z374: Automated Cloud Transition (Groq Integration + Persistence Layer)
6fb88e3
Raw
History Blame Contribute Delete
3.63 kB
const { Pool } = require('pg');
const fs = require('fs');
const path = require('path');
/**
* ZETA DATABASE MANAGER v1.0
* Handles persistent logging for ephemeral cloud environments.
*/
class DatabaseManager {
constructor(logPath) {
this.logPath = logPath;
this.useDB = !!process.env.DATABASE_URL;
this.pool = null;
if (this.useDB) {
console.log('[Z374-DB] 🗄️ Database URL detected. Initializing PostgreSQL pool...');
this.pool = new Pool({
connectionString: process.env.DATABASE_URL,
ssl: { rejectUnauthorized: false } // Required for Supabase/Neon
});
this.initDB();
} else {
console.log('[Z374-DB] 📁 No database detected. Falling back to local file logging.');
}
}
async initDB() {
try {
const client = await this.pool.connect();
await client.query(`
CREATE TABLE IF NOT EXISTS audit_logs (
id SERIAL PRIMARY KEY,
timestamp TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
action TEXT,
details JSONB
);
`);
client.release();
console.log('[Z374-DB] ✅ Database schema verified.');
} catch (e) {
console.error('[Z374-DB] ❌ Database initialization failed:', e.message);
this.useDB = false;
}
}
async log(action, details) {
const timestamp = new Date().toISOString();
const entry = `[${timestamp}] ACTION: ${action} | DETAILS: ${JSON.stringify(details)}\n`;
// Always log to console
console.log(`[AUDIT] ${action}:`, details);
// Persistent DB Logging
if (this.useDB) {
try {
await this.pool.query(
'INSERT INTO audit_logs (action, details) VALUES ($1, $2)',
[action, details]
);
} catch (e) {
console.error('[Z374-DB] ⚠️ DB log failed, falling back to file:', e.message);
}
}
// Local File Logging (Secondary)
try {
fs.appendFileSync(this.logPath, entry);
} catch (e) {
console.error('[Z374-DB] ⚠️ File log failed:', e.message);
}
}
async getLogs(limit = 50) {
if (this.useDB) {
try {
const res = await this.pool.query(
'SELECT timestamp, action, details FROM audit_logs ORDER BY timestamp DESC LIMIT $1',
[limit]
);
return res.rows.map(row =>
`[${row.timestamp.toISOString()}] ACTION: ${row.action} | DETAILS: ${JSON.stringify(row.details)}`
);
} catch (e) {
console.error('[Z374-DB] ⚠️ DB fetch failed:', e.message);
}
}
// Fallback to file
if (!fs.existsSync(this.logPath)) return [];
return fs.readFileSync(this.logPath, 'utf8')
.split('\n')
.filter(l => l)
.reverse()
.slice(0, limit);
}
async purge() {
if (this.useDB) {
try {
await this.pool.query('DELETE FROM audit_logs');
} catch (e) {
console.error('[Z374-DB] ⚠️ DB purge failed:', e.message);
}
}
fs.writeFileSync(this.logPath, `[${new Date().toISOString()}] AUDIT_PURGE: Log cleared by operator.\n`);
}
}
module.exports = DatabaseManager;