feat(boc): v1.0 - Complete Business Operations Center
- Go backend API with full CRUD for all modules - Rust analytics service with parallel processing - C runtime with POSIX shared memory IPC - PostgreSQL schema with 30+ tables - Redis cache, Kafka event streaming - WebSocket hub, automation engine - PDF generation, Resend email integration - JWT auth, multi-tenant - Docker Compose deployment - Nginx reverse proxy Refs: BOC-001
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
func Connect(url string) (*sql.DB, error) {
|
||||
db, err := sql.Open("postgres", url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("db open: %w", err)
|
||||
}
|
||||
|
||||
db.SetMaxOpenConns(25)
|
||||
db.SetMaxIdleConns(10)
|
||||
db.SetConnMaxLifetime(5 * time.Minute)
|
||||
|
||||
if err := db.Ping(); err != nil {
|
||||
db.Close()
|
||||
return nil, fmt.Errorf("db ping: %w", err)
|
||||
}
|
||||
|
||||
if err := autoMigrate(db); err != nil {
|
||||
db.Close()
|
||||
return nil, fmt.Errorf("db migrate: %w", err)
|
||||
}
|
||||
|
||||
return db, nil
|
||||
}
|
||||
|
||||
func autoMigrate(db *sql.DB) error {
|
||||
stmts := []string{
|
||||
`CREATE TABLE IF NOT EXISTS boc_customers (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
email TEXT,
|
||||
phone TEXT,
|
||||
company TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'lead',
|
||||
source TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
)`,
|
||||
|
||||
`CREATE TABLE IF NOT EXISTS boc_deals (
|
||||
id TEXT PRIMARY KEY,
|
||||
customer_id TEXT REFERENCES boc_customers(id),
|
||||
name TEXT NOT NULL,
|
||||
value DECIMAL(12,2) NOT NULL DEFAULT 0,
|
||||
currency TEXT NOT NULL DEFAULT 'SEK',
|
||||
status TEXT NOT NULL DEFAULT 'open',
|
||||
stage TEXT NOT NULL DEFAULT 'prospect',
|
||||
probability INTEGER NOT NULL DEFAULT 0,
|
||||
expected_close TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
)`,
|
||||
|
||||
`CREATE TABLE IF NOT EXISTS boc_invoices (
|
||||
id TEXT PRIMARY KEY,
|
||||
customer_id TEXT REFERENCES boc_customers(id),
|
||||
amount DECIMAL(12,2) NOT NULL DEFAULT 0,
|
||||
currency TEXT NOT NULL DEFAULT 'SEK',
|
||||
status TEXT NOT NULL DEFAULT 'draft',
|
||||
due_date TIMESTAMPTZ,
|
||||
paid_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
)`,
|
||||
|
||||
`CREATE TABLE IF NOT EXISTS boc_tickets (
|
||||
id TEXT PRIMARY KEY,
|
||||
customer_id TEXT REFERENCES boc_customers(id),
|
||||
subject TEXT NOT NULL,
|
||||
status TEXT NOT NULL DEFAULT 'open',
|
||||
priority TEXT NOT NULL DEFAULT 'medium',
|
||||
assigned_to TEXT,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
resolved_at TIMESTAMPTZ
|
||||
)`,
|
||||
|
||||
`CREATE INDEX IF NOT EXISTS idx_customers_status ON boc_customers(status)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_deals_status ON boc_deals(status)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_invoices_status ON boc_invoices(status)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_tickets_status ON boc_tickets(status)`,
|
||||
|
||||
`CREATE TABLE IF NOT EXISTS boc_employees (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
email TEXT,
|
||||
phone TEXT,
|
||||
department TEXT,
|
||||
position TEXT,
|
||||
salary DECIMAL(12,2) NOT NULL DEFAULT 0,
|
||||
currency TEXT NOT NULL DEFAULT 'SEK',
|
||||
start_date TIMESTAMPTZ,
|
||||
status TEXT NOT NULL DEFAULT 'active',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
)`,
|
||||
|
||||
`CREATE INDEX IF NOT EXISTS idx_employees_status ON boc_employees(status)`,
|
||||
}
|
||||
|
||||
for _, s := range stmts {
|
||||
if _, err := db.Exec(s); err != nil {
|
||||
return fmt.Errorf("exec %q: %w", s[:min(40, len(s))], err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func min(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
Reference in New Issue
Block a user