Skip to content

feat(api): add S3 presign endpoints and expand episode/task detail APIs#27

Merged
shark0F0497 merged 3 commits intomainfrom
feat/UI-polish
Apr 12, 2026
Merged

feat(api): add S3 presign endpoints and expand episode/task detail APIs#27
shark0F0497 merged 3 commits intomainfrom
feat/UI-polish

Conversation

@shark0F0497
Copy link
Copy Markdown
Collaborator

Pull Request Checklist

Please ensure your PR meets the following requirements:

  • Code follows the style guidelines
  • Tests pass locally
  • Code is formatted
  • Documentation updated if needed
  • Commit messages follow conventional commits
  • PR description is complete and clear

Summary

This PR adds UI-related backend enhancements including S3 presigned URL endpoints for frontend file access, expanded episode API with more metadata fields, improved task-episode linking, and batch task timestamp improvements.


Motivation

The frontend (synapse) requires access to MCAP and sidecar files stored in MinIO/S3 without exposing direct S3 credentials. Additionally, the episode and task detail APIs need richer data to display comprehensive information to operators and administrators.


Changes

Modified Files

Added Files


Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update (documentation changes only)
  • Refactoring (code improvement without functional changes)
  • Performance improvement (code changes that improve performance)
  • Test changes (adding, modifying, or removing tests)

Impact Analysis

Breaking Changes

None

Backward Compatibility

Fully backward compatible. New endpoints are additive. Existing API responses include additional fields but maintain backward compatibility.


Testing

Test Environment

Local development with MySQL and MinIO

Test Cases

  • Unit tests pass locally
  • Integration tests pass locally
  • E2E tests pass (if applicable)
  • Manual testing completed

Manual Testing Steps

  1. Start keystone with S3 configured
  2. Test GET /api/v1/episodes/:id/presign?kind=mcap returns valid URL
  3. Test GET /api/v1/storage/presign?bucket=test&object=file.mcap returns valid URL
  4. Verify episode detail includes SOP and robot info
  5. Verify task detail includes episode numeric ID and public ID

Test Coverage

  • New tests added
  • Existing tests updated
  • Coverage maintained or improved (not applicable for this PR)

Screenshots / Recordings


Performance Impact

  • Memory usage: No change
  • CPU usage: No change
  • Throughput: No change
  • Lock contention: No change

Documentation


Related Issues

  • Fixes #
  • Related to #
  • Refers to #

Additional Notes

  • The presigned URL expiration is configurable (1-3600 seconds, default 600)
  • Path traversal protection is implemented for bucket and object parameters
  • Authentication is required for storage endpoints unless KEYSTONE_AUTH_ALLOW_NO_AUTH_ON_DEV is enabled

Reviewers

@kilo-code-bot


Notes for Reviewers

  • Please review the S3 presign endpoint security (authentication, path traversal)
  • Verify the DATE_FORMAT fix in batch.go works correctly with MySQL
  • Check if the additional JOINs in episode queries impact performance

Checklist for Reviewers

  • Code changes are correct and well-implemented
  • Tests are adequate and pass
  • Documentation is updated and accurate
  • No unintended side effects
  • Performance impact is acceptable
  • Backward compatibility maintained (if applicable)

// Shape matches GET /api/v1/episodes/:id (Episode): id is episodes.id (PK), episode_id is the human-readable column.
type TaskEpisodeDetail struct {
ID string `json:"id" db:"id"`
ID int64 `json:"id"`
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Breaking API change — ID type changed from string to int64

The JSON output for episode.id in task detail responses changes from "id": "123" to "id": 123. Any client parsing this field as a string will break. Consider using a string-typed field or documenting this as a breaking change.

return bucket, path, true
}

func (h *EpisodeHandler) GetEpisodePresignedURL(c *gin.Context) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Missing authentication check

GetEpisodePresignedURL has no auth verification, unlike StorageHandler.PresignGetObject which validates a Bearer token via auth.ParseToken. The episode routes are registered under v1Routes with no middleware (see server.go:211), so each handler is responsible for its own auth. Without this check, any unauthenticated caller can obtain presigned S3 URLs for any episode by numeric ID.

e.checksum,
COALESCE(e.qa_status, '') as qa_status,
COALESCE(e.qa_score, 0) as qa_score,
e.qa_score,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Behavioral API change — qa_score null handling

Previously COALESCE(e.qa_score, 0) ensured episodes without a QA score returned "qa_score": 0. Now null database values propagate as "qa_score": null in the JSON response. This changes the API contract for any consumer expecting a numeric default.

@kilo-code-bot
Copy link
Copy Markdown

kilo-code-bot bot commented Apr 12, 2026

Code Review Summary

Status: 3 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 3
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
internal/api/handlers/task.go 146 Breaking API change: TaskEpisodeDetail.ID type changed from string to int64
internal/api/handlers/episode.go 383 GetEpisodePresignedURL has no authentication check — unauthenticated users can access presigned S3 URLs
internal/api/handlers/episode.go 204 Removing COALESCE(e.qa_score, 0) changes API response from "qa_score": 0 to "qa_score": null
Other Observations (not in diff)
File Line Issue
internal/api/handlers/batch.go 1037, 1423 assigned_at is set to now for tasks created in 'pending' status (same pattern as task.go:864). This is consistent across the PR but semantically questionable — consider whether assigned_at should be NULL until the task is actually assigned.
Files Reviewed (6 files)
  • internal/api/handlers/batch.go - 0 issues (DATE_FORMAT fix is correct)
  • internal/api/handlers/episode.go - 2 issues (TrimPrefix refactor in latest commit is functionally equivalent ✓)
  • internal/api/handlers/storage.go - 0 issues (auth + path traversal checks look good)
  • internal/api/handlers/task.go - 1 issue
  • internal/api/handlers/transfer.go - 0 issues (bucket prefix change is consistent)
  • internal/server/server.go - 0 issues

Incremental review: checked new commits since db29d157c49589. No new issues introduced; all 3 previous issues remain unresolved.

Fix these issues in Kilo Cloud


Reviewed by glm-5 · 112,320 tokens

@shark0F0497 shark0F0497 merged commit 68f465d into main Apr 12, 2026
6 checks passed
@shark0F0497 shark0F0497 deleted the feat/UI-polish branch April 12, 2026 15:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant