AuditController.java

package com.rbctcsworld.ecommerce.audit;

import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * Store admin only (/api/admin/**). Read-only: there is no endpoint that changes or deletes audit rows.
 * GET /api/admin/audit?entityType=PRODUCT&entityId=5&actor=a@b.com&limit=200  newest first | 400 bad limit
 * GET /api/admin/audit/verify                                               {valid, entries, brokenAtSeq, reason}
 * GET /api/admin/audit/export?...                                           text/csv download
 */
@RestController
@RequestMapping("/api/admin/audit")
public class AuditController {

    private final AuditService audit;

    public AuditController(AuditService audit) {
        this.audit = audit;
    }

    @GetMapping
    public List<AuditRecord> find(@RequestParam(required = false) String entityType,
                                  @RequestParam(required = false) Long entityId,
                                  @RequestParam(required = false) String actor,
                                  @RequestParam(required = false) Integer limit) {
        return audit.find(entityType, entityId, actor, limit);
    }

    @GetMapping("/verify")
    public AuditChain.Verification verify() {
        return audit.verify();
    }

    @GetMapping("/export")
    public ResponseEntity<String> export(@RequestParam(required = false) String entityType,
                                         @RequestParam(required = false) Long entityId,
                                         @RequestParam(required = false) String actor) {
        return ResponseEntity.ok()
                .contentType(new MediaType("text", "csv", java.nio.charset.StandardCharsets.UTF_8))
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"audit-trail.csv\"")
                .body(audit.csv(entityType, entityId, actor));
    }
}