GitStateController.java

package com.taxonomy.versioning.controller;

import com.taxonomy.dto.ProjectionState;
import com.taxonomy.dto.RepositoryState;
import com.taxonomy.versioning.service.RepositoryStateService;
import com.taxonomy.workspace.service.WorkspaceResolver;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

/**
 * REST API for querying the Git repository state.
 *
 * <p>Exposes the current branch, HEAD commit, projection/index freshness,
 * and branch overview. All data comes from {@link RepositoryStateService}
 * which combines JGit repository metadata with per-user projection tracking.
 */
@RestController
@RequestMapping("/api/git")
@Tag(name = "Git Repository State")
public class GitStateController {

    private final RepositoryStateService stateService;
    private final WorkspaceResolver workspaceResolver;

    public GitStateController(RepositoryStateService stateService,
                              WorkspaceResolver workspaceResolver) {
        this.stateService = stateService;
        this.workspaceResolver = workspaceResolver;
    }

    @GetMapping("/state")
    @Operation(summary = "Full repository state including projection/index staleness",
            description = "Returns the complete repository state snapshot for a branch, " +
                    "including HEAD commit info, all branches, projection/index freshness, " +
                    "and any in-progress operations.")
    public ResponseEntity<RepositoryState> getState(
            @RequestParam(defaultValue = "draft") String branch) {
        String user = workspaceResolver.resolveCurrentUsername();
        return ResponseEntity.ok(stateService.getState(user, branch));
    }

    @GetMapping("/projection")
    @Operation(summary = "Projection and search index freshness",
            description = "Returns which commit the DB projection and search index are " +
                    "built from, and whether they are stale relative to HEAD.")
    public ResponseEntity<ProjectionState> getProjectionState(
            @RequestParam(defaultValue = "draft") String branch) {
        String user = workspaceResolver.resolveCurrentUsername();
        return ResponseEntity.ok(stateService.getProjectionState(user, branch));
    }

    @GetMapping("/branches")
    @Operation(summary = "List all branches with HEAD commit info",
            description = "Returns all Git branches in the repository with their " +
                    "HEAD commit SHA and basic metadata.")
    public ResponseEntity<RepositoryState> listBranches(
            @RequestParam(defaultValue = "draft") String branch) {
        String user = workspaceResolver.resolveCurrentUsername();
        return ResponseEntity.ok(stateService.getState(user, branch));
    }

    @GetMapping("/stale")
    @Operation(summary = "Quick check: is projection/index stale?",
            description = "Lightweight endpoint returning only staleness flags. " +
                    "Useful for periodic polling from the UI.")
    public ResponseEntity<Map<String, Boolean>> isStale(
            @RequestParam(defaultValue = "draft") String branch) {
        String user = workspaceResolver.resolveCurrentUsername();
        ProjectionState ps = stateService.getProjectionState(user, branch);
        return ResponseEntity.ok(Map.of(
                "projectionStale", ps.projectionStale(),
                "indexStale", ps.indexStale()
        ));
    }
}