feat: improve timeline/admin flows and ingest projection repairs

This commit is contained in:
2026-03-01 00:21:31 +03:00
parent c805daabcf
commit 229db81229
26 changed files with 2873 additions and 270 deletions

View File

@@ -47,6 +47,57 @@ func writeTimelineResponse(w http.ResponseWriter, r *http.Request, repo *timelin
})
}
func writeImportHistoryResponse(w http.ResponseWriter, r *http.Request, repo *timeline.EventRepository, subjectType string, subjectID string) {
limit := 20
if raw := r.URL.Query().Get("limit"); raw != "" {
if parsed, err := strconv.Atoi(raw); err == nil {
limit = parsed
} else {
writeError(w, http.StatusBadRequest, "invalid limit")
return
}
}
var cursor *timeline.Cursor
if raw := r.URL.Query().Get("cursor"); raw != "" {
decoded, err := timeline.DecodeCursor(raw)
if err != nil {
writeError(w, http.StatusBadRequest, "invalid cursor")
return
}
cursor = &decoded
}
var (
items []timeline.ImportHistoryItem
next *timeline.Cursor
err error
)
switch subjectType {
case "asset":
items, next, err = repo.ListAssetImportHistory(r.Context(), subjectID, limit, cursor)
case "component":
items, next, err = repo.ListComponentImportHistory(r.Context(), subjectID, limit, cursor)
default:
writeError(w, http.StatusBadRequest, "unsupported subject type")
return
}
if err != nil {
writeError(w, http.StatusInternalServerError, "list import history failed")
return
}
var nextCursor *string
if next != nil {
value := timeline.EncodeCursor(*next)
nextCursor = &value
}
writeJSON(w, http.StatusOK, map[string]any{
"items": items,
"next_cursor": nextCursor,
})
}
func parseTimelineID(path, prefix string) string {
if !strings.HasPrefix(path, prefix) || !strings.HasSuffix(path, "/timeline") {
return ""