package db import ( "context" "encoding/json" "github.com/flatrender/notification-svc/internal/models" "github.com/google/uuid" "github.com/jackc/pgx/v5" ) // ── Channel provider config ────────────────────────────────────────────────── func (s *Store) GetChannelConfigs(ctx context.Context, tenantID uuid.UUID) ([]*models.ChannelConfig, error) { rows, err := s.pool.Query(ctx, `SELECT tenant_id, channel, settings, enabled, updated_at FROM notification.channel_config WHERE tenant_id = $1 ORDER BY channel`, tenantID) if err != nil { return nil, err } defer rows.Close() var out []*models.ChannelConfig for rows.Next() { c := &models.ChannelConfig{} var raw []byte if err := rows.Scan(&c.TenantID, &c.Channel, &raw, &c.Enabled, &c.UpdatedAt); err != nil { return nil, err } _ = json.Unmarshal(raw, &c.Settings) out = append(out, c) } return out, rows.Err() } func (s *Store) GetChannelConfig(ctx context.Context, tenantID uuid.UUID, channel string) (*models.ChannelConfig, error) { c := &models.ChannelConfig{} var raw []byte err := s.pool.QueryRow(ctx, `SELECT tenant_id, channel, settings, enabled, updated_at FROM notification.channel_config WHERE tenant_id = $1 AND channel = $2`, tenantID, channel). Scan(&c.TenantID, &c.Channel, &raw, &c.Enabled, &c.UpdatedAt) if err == pgx.ErrNoRows { return nil, nil } if err != nil { return nil, err } _ = json.Unmarshal(raw, &c.Settings) return c, nil } func (s *Store) UpsertChannelConfig(ctx context.Context, tenantID uuid.UUID, channel string, settings map[string]any, enabled bool) error { raw, _ := json.Marshal(settings) _, err := s.pool.Exec(ctx, `INSERT INTO notification.channel_config (tenant_id, channel, settings, enabled, updated_at) VALUES ($1, $2, $3, $4, NOW()) ON CONFLICT (tenant_id, channel) DO UPDATE SET settings = EXCLUDED.settings, enabled = EXCLUDED.enabled, updated_at = NOW()`, tenantID, channel, raw, enabled) return err } // ── Email template lookup ──────────────────────────────────────────────────── func (s *Store) GetEmailTemplate(ctx context.Context, code, locale string) (*models.NotificationTemplate, error) { t := &models.NotificationTemplate{} err := s.pool.QueryRow(ctx, `SELECT id, code, channel, locale, subject, body_text, body_html, is_active FROM notification.notification_templates WHERE code = $1 AND channel = 'Email' AND locale = $2 AND is_active = TRUE LIMIT 1`, code, locale). Scan(&t.ID, &t.Code, &t.Channel, &t.Locale, &t.Subject, &t.BodyText, &t.BodyHTML, &t.IsActive) if err == pgx.ErrNoRows { return nil, nil } return t, err } // ── Delivery log ───────────────────────────────────────────────────────────── func (s *Store) LogDelivery(ctx context.Context, tenantID, userID uuid.UUID, channel, recipient string, subject, provider, providerMsgID, status, errMsg *string) error { _, err := s.pool.Exec(ctx, `INSERT INTO notification.notification_deliveries (tenant_id, user_id, channel, recipient, subject, provider, provider_message_id, status, error_message, sent_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, NOW())`, tenantID, userID, channel, recipient, subject, provider, providerMsgID, status, errMsg) return err }