package services import ( "context" "database/sql" "strings" "github.com/rede5/gohorsejobs/backend/internal/models" ) type AuditService struct { DB *sql.DB } func NewAuditService(db *sql.DB) *AuditService { return &AuditService{DB: db} } type LoginAuditInput struct { UserID string Identifier string Roles []string IPAddress *string UserAgent *string } func (s *AuditService) RecordLogin(ctx context.Context, input LoginAuditInput) error { roles := strings.Join(input.Roles, ",") query := ` INSERT INTO login_audit (user_id, identifier, roles, ip_address, user_agent) VALUES ($1, $2, $3, $4, $5) ` _, err := s.DB.ExecContext(ctx, query, input.UserID, input.Identifier, roles, input.IPAddress, input.UserAgent) return err } func (s *AuditService) ListLogins(ctx context.Context, limit int) ([]models.LoginAudit, error) { if limit <= 0 { limit = 50 } query := ` SELECT id, user_id, identifier, roles, ip_address, user_agent, created_at FROM login_audit ORDER BY created_at DESC LIMIT $1 ` rows, err := s.DB.QueryContext(ctx, query, limit) if err != nil { return nil, err } defer rows.Close() var audits []models.LoginAudit for rows.Next() { var entry models.LoginAudit if err := rows.Scan( &entry.ID, &entry.UserID, &entry.Identifier, &entry.Roles, &entry.IPAddress, &entry.UserAgent, &entry.CreatedAt, ); err != nil { return nil, err } audits = append(audits, entry) } return audits, nil }