Install LOC guardrails (check-loc.sh, architecture.md, pre-commit hook) and split all 44 files exceeding 500 LOC into domain-focused modules: - consent-service (Go): models, handlers, services, database splits - backend-core (Python): security_api, rbac_api, pdf_service, auth splits - admin-core (TypeScript): 5 page.tsx + sidebar extractions - pitch-deck (TypeScript): 6 slides, 3 UI components, engine.ts splits - voice-service (Python): enhanced_task_orchestrator split Result: 0 violations, 36 exempted (pipeline, tests, pure-data files). Go build verified clean. No behavior changes — pure structural splits. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
115 lines
4.1 KiB
Go
115 lines
4.1 KiB
Go
package database
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
)
|
|
|
|
// migrateEmail creates email template tables, settings, and indexes (Phase 8).
|
|
func migrateEmail(db *DB) error {
|
|
ctx := context.Background()
|
|
|
|
migrations := []string{
|
|
// =============================================
|
|
// Phase 8: E-Mail Templates (Transactional)
|
|
// =============================================
|
|
|
|
// Email templates (like legal_documents)
|
|
`CREATE TABLE IF NOT EXISTS email_templates (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
type VARCHAR(50) UNIQUE NOT NULL,
|
|
name VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
is_active BOOLEAN DEFAULT TRUE,
|
|
sort_order INT DEFAULT 0,
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ DEFAULT NOW()
|
|
)`,
|
|
|
|
// Email template versions (like document_versions)
|
|
`CREATE TABLE IF NOT EXISTS email_template_versions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
template_id UUID REFERENCES email_templates(id) ON DELETE CASCADE,
|
|
version VARCHAR(20) NOT NULL,
|
|
language VARCHAR(5) DEFAULT 'de',
|
|
subject VARCHAR(500) NOT NULL,
|
|
body_html TEXT NOT NULL,
|
|
body_text TEXT NOT NULL,
|
|
summary TEXT,
|
|
status VARCHAR(20) DEFAULT 'draft',
|
|
published_at TIMESTAMPTZ,
|
|
scheduled_publish_at TIMESTAMPTZ,
|
|
created_by UUID REFERENCES users(id),
|
|
approved_by UUID REFERENCES users(id),
|
|
approved_at TIMESTAMPTZ,
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
|
UNIQUE(template_id, version, language)
|
|
)`,
|
|
|
|
// Email template approvals (like version_approvals)
|
|
`CREATE TABLE IF NOT EXISTS email_template_approvals (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
version_id UUID REFERENCES email_template_versions(id) ON DELETE CASCADE,
|
|
approver_id UUID REFERENCES users(id),
|
|
action VARCHAR(30) NOT NULL,
|
|
comment TEXT,
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
)`,
|
|
|
|
// Email send logs for audit
|
|
`CREATE TABLE IF NOT EXISTS email_send_logs (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID REFERENCES users(id) ON DELETE SET NULL,
|
|
version_id UUID REFERENCES email_template_versions(id) ON DELETE SET NULL,
|
|
recipient VARCHAR(255) NOT NULL,
|
|
subject VARCHAR(500) NOT NULL,
|
|
status VARCHAR(20) DEFAULT 'queued',
|
|
error_msg TEXT,
|
|
variables JSONB,
|
|
sent_at TIMESTAMPTZ,
|
|
delivered_at TIMESTAMPTZ,
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
)`,
|
|
|
|
// Global email settings (logo, colors, signature)
|
|
`CREATE TABLE IF NOT EXISTS email_template_settings (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
logo_url TEXT,
|
|
logo_base64 TEXT,
|
|
company_name VARCHAR(255) DEFAULT 'BreakPilot',
|
|
sender_name VARCHAR(255) DEFAULT 'BreakPilot',
|
|
sender_email VARCHAR(255) DEFAULT 'noreply@breakpilot.app',
|
|
reply_to_email VARCHAR(255),
|
|
footer_html TEXT,
|
|
footer_text TEXT,
|
|
primary_color VARCHAR(7) DEFAULT '#2563eb',
|
|
secondary_color VARCHAR(7) DEFAULT '#64748b',
|
|
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
|
updated_by UUID REFERENCES users(id)
|
|
)`,
|
|
|
|
// Insert default email settings
|
|
`INSERT INTO email_template_settings (id, company_name, sender_name, sender_email, primary_color, secondary_color)
|
|
VALUES (gen_random_uuid(), 'BreakPilot', 'BreakPilot', 'noreply@breakpilot.app', '#2563eb', '#64748b')
|
|
ON CONFLICT DO NOTHING`,
|
|
|
|
// Phase 8 Indexes
|
|
`CREATE INDEX IF NOT EXISTS idx_email_templates_type ON email_templates(type)`,
|
|
`CREATE INDEX IF NOT EXISTS idx_email_template_versions_template ON email_template_versions(template_id)`,
|
|
`CREATE INDEX IF NOT EXISTS idx_email_template_versions_status ON email_template_versions(status)`,
|
|
`CREATE INDEX IF NOT EXISTS idx_email_template_approvals_version ON email_template_approvals(version_id)`,
|
|
`CREATE INDEX IF NOT EXISTS idx_email_send_logs_user ON email_send_logs(user_id)`,
|
|
`CREATE INDEX IF NOT EXISTS idx_email_send_logs_created ON email_send_logs(created_at)`,
|
|
`CREATE INDEX IF NOT EXISTS idx_email_send_logs_status ON email_send_logs(status)`,
|
|
}
|
|
|
|
for _, migration := range migrations {
|
|
if _, err := db.Pool.Exec(ctx, migration); err != nil {
|
|
return fmt.Errorf("migrateEmail: %w", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|