This commit is contained in:
2026-03-13 22:30:55 +01:00
parent 19f4e07b4d
commit c5a3f5607d
6 changed files with 113 additions and 1 deletions

View File

@@ -2,12 +2,16 @@ package com.posthub.analytics.controller;
import com.posthub.analytics.dto.DailyStatsResponse;
import com.posthub.analytics.dto.DashboardResponse;
import com.posthub.analytics.dto.EventLogResponse;
import com.posthub.analytics.model.UserStats;
import com.posthub.analytics.service.AnalyticsQueryService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDate;
import java.util.List;
@RestController
@@ -34,4 +38,14 @@ public class AnalyticsController {
return ResponseEntity.ok(queryService.getDailyStats(days));
}
@GetMapping("/events")
public ResponseEntity<Page<EventLogResponse>> getEvents(
@RequestParam(required = false) String eventType,
@RequestParam(required = false) String userId,
@RequestParam(required = false) LocalDate dateFrom,
@RequestParam(required = false) LocalDate dateTo,
Pageable pageable) {
return ResponseEntity.ok(queryService.getEvents(eventType, userId, dateFrom, dateTo, pageable));
}
}

View File

@@ -0,0 +1,23 @@
package com.posthub.analytics.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.Instant;
import java.time.LocalDate;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class EventLogResponse {
private Long id;
private String eventType;
private String userId;
private String chatId;
private Instant eventTimestamp;
private LocalDate eventDate;
}

View File

@@ -2,6 +2,7 @@ package com.posthub.analytics.repository;
import com.posthub.analytics.model.EventLog;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
@@ -10,7 +11,7 @@ import java.time.LocalDate;
import java.util.List;
@Repository
public interface EventLogRepository extends JpaRepository<EventLog, Long> {
public interface EventLogRepository extends JpaRepository<EventLog, Long>, JpaSpecificationExecutor<EventLog> {
@Query("SELECT COUNT(DISTINCT e.userId) FROM EventLog e " +
"WHERE e.eventDate BETWEEN :from AND :to")

View File

@@ -0,0 +1,35 @@
package com.posthub.analytics.repository;
import com.posthub.analytics.model.EventLog;
import org.springframework.data.jpa.domain.Specification;
import java.time.LocalDate;
public final class EventLogSpecification {
private EventLogSpecification() {}
public static Specification<EventLog> hasEventType(String eventType) {
return (root, query, cb) -> eventType == null || eventType.isBlank()
? null
: cb.equal(root.get("eventType"), eventType);
}
public static Specification<EventLog> hasUserId(String userId) {
return (root, query, cb) -> userId == null || userId.isBlank()
? null
: cb.equal(root.get("userId"), userId);
}
public static Specification<EventLog> dateFrom(LocalDate dateFrom) {
return (root, query, cb) -> dateFrom == null
? null
: cb.greaterThanOrEqualTo(root.get("eventDate"), dateFrom);
}
public static Specification<EventLog> dateTo(LocalDate dateTo) {
return (root, query, cb) -> dateTo == null
? null
: cb.lessThanOrEqualTo(root.get("eventDate"), dateTo);
}
}

View File

@@ -2,12 +2,18 @@ package com.posthub.analytics.service;
import com.posthub.analytics.dto.DailyStatsResponse;
import com.posthub.analytics.dto.DashboardResponse;
import com.posthub.analytics.dto.EventLogResponse;
import com.posthub.analytics.model.DailyStats;
import com.posthub.analytics.model.EventLog;
import com.posthub.analytics.model.UserStats;
import com.posthub.analytics.repository.DailyStatsRepository;
import com.posthub.analytics.repository.EventLogRepository;
import com.posthub.analytics.repository.EventLogSpecification;
import com.posthub.analytics.repository.UserStatsRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -76,4 +82,28 @@ public class AnalyticsQueryService {
.activeUsers(ds.getActiveUsers())
.build();
}
public Page<EventLogResponse> getEvents(String eventType, String userId,
LocalDate dateFrom, LocalDate dateTo,
Pageable pageable) {
Specification<EventLog> spec = Specification
.where(EventLogSpecification.hasEventType(eventType))
.and(EventLogSpecification.hasUserId(userId))
.and(EventLogSpecification.dateFrom(dateFrom))
.and(EventLogSpecification.dateTo(dateTo));
return eventLogRepository.findAll(spec, pageable)
.map(this::toEventResponse);
}
private EventLogResponse toEventResponse(EventLog e) {
return EventLogResponse.builder()
.id(e.getId())
.eventType(e.getEventType())
.userId(e.getUserId())
.chatId(e.getChatId())
.eventTimestamp(e.getEventTimestamp())
.eventDate(e.getEventDate())
.build();
}
}

View File

@@ -61,6 +61,15 @@ spring:
- RewritePath=/api/rag(?<segment>/?.*), ${segment}
- AddRequestHeader=X-Forwarded-Prefix, /api/rag
# Analytics Service - API endpoints
- id: analytics-service-api
uri: lb://analytics-service
predicates:
- Path=/api/analytics/**
- Method=GET,POST
filters:
- AddRequestHeader=X-Forwarded-Prefix, /api/analytics
# ---- JWT ----
jwt:
secret: ${JWT_SECRET:}