feat: Enhance provider components with detailed documentation and comments
- Added comprehensive comments and JSDoc-style documentation to NotificationProvider, ThemeProvider, UserProvider, and WebsiteThemeProvider for better clarity and maintainability. - Improved type definitions in index.ts for better code understanding and usage. - Introduced Docker support with Dockerfiles for various services including AI server, signaling server, and browser-use service. - Created a docker-compose.yml file to orchestrate multiple services including PostgreSQL, AI, scraper, and frontend. - Added a startup guide (startup.txt) for setting up the CRM environment on Ubuntu with Docker. - Included a .dockerignore file to exclude unnecessary files from Docker builds.
This commit is contained in:
@@ -14,6 +14,8 @@ const __dirname = dirname(fileURLToPath(import.meta.url))
|
||||
const ROOT = resolve(__dirname, "..")
|
||||
|
||||
// ── Load .env.local into process.env ─────────────────────────────────
|
||||
// Simple key=value parser (no dotenv dependency needed).
|
||||
// Handles quoted values and skips comments / blank lines.
|
||||
|
||||
const envPath = resolve(ROOT, ".env.local")
|
||||
if (existsSync(envPath)) {
|
||||
@@ -24,9 +26,11 @@ if (existsSync(envPath)) {
|
||||
if (eq === -1) continue
|
||||
const key = trimmed.slice(0, eq).trim()
|
||||
let value = trimmed.slice(eq + 1).trim()
|
||||
// Strip matching surrounding quotes (single or double)
|
||||
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
||||
value = value.slice(1, -1)
|
||||
}
|
||||
// Don't override already-set env vars
|
||||
if (!process.env[key]) process.env[key] = value
|
||||
}
|
||||
}
|
||||
@@ -38,6 +42,7 @@ if (!DATABASE_URL) {
|
||||
}
|
||||
|
||||
// ── Find psql ────────────────────────────────────────────────────────
|
||||
// Check PATH first, then probe common PostgreSQL v14–17 install paths.
|
||||
|
||||
function findPsql() {
|
||||
try {
|
||||
@@ -84,8 +89,9 @@ try {
|
||||
|
||||
// ── Migration logic ──────────────────────────────────────────────────
|
||||
|
||||
/** Run all unapplied database migrations in the order defined by run_all.sql. */
|
||||
async function runMigrations() {
|
||||
// 1. Create tracking table if not exists
|
||||
// 1. Ensure the _migrations tracking table exists (idempotent)
|
||||
await pool.query(`
|
||||
CREATE TABLE IF NOT EXISTS _migrations (
|
||||
id SERIAL PRIMARY KEY,
|
||||
@@ -94,11 +100,12 @@ async function runMigrations() {
|
||||
)
|
||||
`)
|
||||
|
||||
// 2. Determine file order from run_all.sql (authoritative)
|
||||
// 2. Determine file order from run_all.sql (authoritative source of truth)
|
||||
const runAllPath = resolve(ROOT, "database", "migrations", "run_all.sql")
|
||||
const runAllContent = readFileSync(runAllPath, "utf-8")
|
||||
const fileOrder = []
|
||||
for (const line of runAllContent.split("\n")) {
|
||||
// `\i filename.sql` is the psql include directive
|
||||
const match = line.match(/\\i\s+(\S+\.sql)/)
|
||||
if (match) fileOrder.push(match[1])
|
||||
}
|
||||
@@ -117,7 +124,7 @@ async function runMigrations() {
|
||||
appliedSet = new Set()
|
||||
}
|
||||
|
||||
// 4. Build psql command base
|
||||
// 4. Build psql command base with ON_ERROR_STOP=1 so psql aborts on first error
|
||||
const psqlCmd = `${PSQL} -d "${DATABASE_URL}" -v ON_ERROR_STOP=1`
|
||||
|
||||
// 5. Run unapplied files in order.
|
||||
@@ -133,6 +140,7 @@ async function runMigrations() {
|
||||
|
||||
let count = 0
|
||||
for (const file of fileOrder) {
|
||||
// Skip files already recorded in the _migrations table
|
||||
if (appliedSet.has(file)) continue
|
||||
|
||||
const filePath = resolve(ROOT, "database", "migrations", file)
|
||||
@@ -149,12 +157,14 @@ async function runMigrations() {
|
||||
maxBuffer: 10 * 1024 * 1024,
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
})
|
||||
// psql outputs notices/warnings to stderr even on success
|
||||
// psql outputs notices/warnings to stderr even on success — capture for diagnostics
|
||||
stderr = result.stderr || ""
|
||||
} catch (err) {
|
||||
// Distinguish between "already applied" (harmless) and genuine failures
|
||||
const msg = err.stderr || err.stdout || err.message
|
||||
const isAlreadyApplied = ALREADY_APPLIED_PATTERNS.some((p) => msg.includes(p))
|
||||
if (isAlreadyApplied) {
|
||||
// File was applied before tracking existed — record it and continue
|
||||
await pool.query("INSERT INTO _migrations (filename) VALUES ($1) ON CONFLICT DO NOTHING", [file])
|
||||
console.log(` ~ Already applied: ${file}`)
|
||||
count++
|
||||
@@ -165,6 +175,7 @@ async function runMigrations() {
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
// Record successful migration
|
||||
await pool.query("INSERT INTO _migrations (filename) VALUES ($1)", [file])
|
||||
console.log(` ✓ Applied: ${file}`)
|
||||
count++
|
||||
|
||||
Reference in New Issue
Block a user