Files
boc/backend/db/db.go
T
Bernt (LandveX AI) 67a69ab073 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
2026-07-12 13:21:10 +00:00

120 lines
3.1 KiB
Go

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
}