Add database migration scripts and configuration files

- Add verify-migration.js script for testing database migrations
- Add database config module for centralized configuration
- Add chutes.txt prompt for system responses
- Update database implementation and testing documentation
- Add database migration and setup scripts
- Update session system and LLM tool configuration
- Update deployment checklist and environment example
- Update Dockerfile and docker-compose configuration
This commit is contained in:
southseact-3d
2026-02-20 12:38:43 +00:00
parent a92797d3a7
commit cb95a916ae
19 changed files with 1104 additions and 143 deletions

View File

@@ -0,0 +1,21 @@
const path = require('path');
function resolvePath(root, value, fallback) {
if (!value) return fallback;
if (path.isAbsolute(value)) return value;
return path.join(root, value);
}
const DATA_ROOT = process.env.CHAT_DATA_ROOT || path.join(process.cwd(), '.data');
const STATE_DIR = path.join(DATA_ROOT, '.opencode-chat');
const DEFAULT_DB_PATH = path.join(DATA_ROOT, '.data', 'shopify_ai.db');
const DB_PATH = resolvePath(DATA_ROOT, process.env.DATABASE_PATH, DEFAULT_DB_PATH);
const DEFAULT_KEY_FILE = path.join(path.dirname(DB_PATH), '.encryption_key');
const KEY_FILE = resolvePath(DATA_ROOT, process.env.DATABASE_KEY_FILE, DEFAULT_KEY_FILE);
module.exports = {
DATA_ROOT,
STATE_DIR,
DB_PATH,
KEY_FILE
};

View File

@@ -1,7 +1,7 @@
/**
* Database connection module with SQLite support
* Uses better-sqlite3 for synchronous operations
* Note: SQLCipher support requires special compilation, using AES-256-GCM encryption at field level instead
* Note: SQLCipher support requires special compilation and is enabled via configuration
*/
const Database = require('better-sqlite3');
@@ -11,6 +11,10 @@ const fs = require('fs');
let db = null;
let dbPath = null;
function escapeSqliteString(value) {
return String(value || '').replace(/'/g, "''");
}
/**
* Initialize database connection
* @param {string} databasePath - Path to the database file
@@ -43,6 +47,18 @@ function initDatabase(databasePath, options = {}) {
db = new Database(databasePath, dbOptions);
// SQLCipher support (optional)
if (options.sqlcipherKey) {
const escapedKey = escapeSqliteString(options.sqlcipherKey);
db.pragma(`key = '${escapedKey}'`);
if (options.cipherCompatibility) {
db.pragma(`cipher_compatibility = ${Number(options.cipherCompatibility)}`);
}
if (options.kdfIter) {
db.pragma(`kdf_iter = ${Number(options.kdfIter)}`);
}
}
// Enable WAL mode for better concurrency
if (options.walMode !== false) {
db.pragma('journal_mode = WAL');

View File

@@ -31,7 +31,8 @@ CREATE TABLE IF NOT EXISTS users (
two_factor_enabled INTEGER DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
last_login_at INTEGER
last_login_at INTEGER,
data TEXT -- Full user payload (JSON)
);
-- Sessions table for active user sessions
@@ -92,6 +93,24 @@ CREATE TABLE IF NOT EXISTS affiliates (
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
-- Affiliate accounts (used by current app)
CREATE TABLE IF NOT EXISTS affiliate_accounts (
id TEXT PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
name TEXT,
password_hash TEXT NOT NULL,
codes TEXT NOT NULL DEFAULT '[]', -- JSON array of tracking codes
earnings TEXT NOT NULL DEFAULT '[]', -- JSON array of earnings
commission_rate REAL NOT NULL DEFAULT 0.15,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
last_login_at TEXT,
last_payout_at TEXT,
email_verified INTEGER DEFAULT 0,
verification_token TEXT,
verification_expires_at TEXT
);
-- Withdrawals table
CREATE TABLE IF NOT EXISTS withdrawals (
id TEXT PRIMARY KEY,
@@ -172,6 +191,7 @@ CREATE INDEX IF NOT EXISTS idx_refresh_tokens_token_hash ON refresh_tokens(token
CREATE INDEX IF NOT EXISTS idx_token_blacklist_token_jti ON token_blacklist(token_jti);
CREATE INDEX IF NOT EXISTS idx_token_blacklist_expires_at ON token_blacklist(expires_at);
CREATE INDEX IF NOT EXISTS idx_affiliates_user_id ON affiliates(user_id);
CREATE INDEX IF NOT EXISTS idx_affiliate_accounts_email ON affiliate_accounts(email);
CREATE INDEX IF NOT EXISTS idx_withdrawals_affiliate_id ON withdrawals(affiliate_id);
CREATE INDEX IF NOT EXISTS idx_feature_requests_user_id ON feature_requests(user_id);
CREATE INDEX IF NOT EXISTS idx_audit_log_user_id ON audit_log(user_id);