package service import ( "context" "encoding/json" "net/http" "tailly_back_v2/internal/domain" "tailly_back_v2/internal/repository" "time" ) type AuditService interface { LogEvent( ctx context.Context, action string, entityType string, entityID *int, r *http.Request, status string, metadata interface{}, ) error GetEvents(ctx context.Context, filter domain.AuditFilter) ([]*domain.AuditLog, error) ExportEvents(ctx context.Context, filter domain.AuditFilter) ([]byte, error) } type auditService struct { auditRepo repository.AuditRepository } func NewAuditService(auditRepo repository.AuditRepository) AuditService { return &auditService{ auditRepo: auditRepo, } } func (s *auditService) LogEvent( ctx context.Context, action string, entityType string, entityID *int, r *http.Request, status string, metadata interface{}, ) error { var userID *int if ctxUserID, ok := ctx.Value("userID").(int); ok { userID = &ctxUserID } metadataJSON, err := json.Marshal(metadata) if err != nil { return err } ip := r.Header.Get("X-Forwarded-For") if ip == "" { ip = r.RemoteAddr } log := &domain.AuditLog{ UserID: userID, Action: action, EntityType: entityType, EntityID: entityID, IPAddress: ip, UserAgent: r.UserAgent(), Metadata: string(metadataJSON), Status: status, CreatedAt: time.Now(), } return s.auditRepo.Save(ctx, log) } func (s *auditService) GetEvents(ctx context.Context, filter domain.AuditFilter) ([]*domain.AuditLog, error) { if filter.Limit == 0 { filter.Limit = 50 } return s.auditRepo.Get(ctx, filter) } func (s *auditService) ExportEvents(ctx context.Context, filter domain.AuditFilter) ([]byte, error) { logs, err := s.auditRepo.Get(ctx, filter) if err != nil { return nil, err } return json.Marshal(logs) }