feat: implement audit repo and service
AuditRepo.Log resolves action_type_id/object_type_id via SQL subqueries. AuditRepo.List supports dynamic filtering by user, action, object type/ID, and date range with COUNT(*) OVER() for total count. AuditService.Log reads user from context, marshals details to JSON, and delegates to the repo. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"tanabata/backend/internal/domain"
|
||||
"tanabata/backend/internal/port"
|
||||
)
|
||||
|
||||
// AuditService records user actions to the audit trail.
|
||||
type AuditService struct {
|
||||
repo port.AuditRepo
|
||||
}
|
||||
|
||||
func NewAuditService(repo port.AuditRepo) *AuditService {
|
||||
return &AuditService{repo: repo}
|
||||
}
|
||||
|
||||
// Log records an action performed by the user in ctx.
|
||||
// objectType and objectID are optional — pass nil when the action has no target object.
|
||||
// details can be any JSON-serializable value, or nil.
|
||||
func (s *AuditService) Log(
|
||||
ctx context.Context,
|
||||
action string,
|
||||
objectType *string,
|
||||
objectID *uuid.UUID,
|
||||
details any,
|
||||
) error {
|
||||
userID, _, _ := domain.UserFromContext(ctx)
|
||||
|
||||
var raw json.RawMessage
|
||||
if details != nil {
|
||||
b, err := json.Marshal(details)
|
||||
if err != nil {
|
||||
return fmt.Errorf("AuditService.Log marshal details: %w", err)
|
||||
}
|
||||
raw = b
|
||||
}
|
||||
|
||||
entry := domain.AuditEntry{
|
||||
UserID: userID,
|
||||
Action: action,
|
||||
ObjectType: objectType,
|
||||
ObjectID: objectID,
|
||||
Details: raw,
|
||||
}
|
||||
return s.repo.Log(ctx, entry)
|
||||
}
|
||||
|
||||
// Query returns a filtered, paginated page of audit log entries.
|
||||
func (s *AuditService) Query(ctx context.Context, filter domain.AuditFilter) (*domain.AuditPage, error) {
|
||||
return s.repo.List(ctx, filter)
|
||||
}
|
||||
Reference in New Issue
Block a user