feat(storage): integrate Cloudflare R2 for object storage - #31
Conversation
Wires the existing R2 infrastructure layer end-to-end across all three app layers. The service is optional — enabled only when R2_ACCOUNT_ID is set in the environment. Backend: - Add StorageService interface to usecase/ (Clean Architecture placement) - Update r2.New() to return usecase.StorageService; add NewWithHTTPClient constructor for test injection via custom RoundTripper - Bootstrap: add R2 config fields, App.StorageService, and init block - POST /api/v1/storage/presign — returns presigned PUT URL + public URL - DELETE /api/v1/storage/:key — deletes an object; both routes require Firebase auth and are gated on h.storageService != nil - Regenerate Swagger docs; add R2 vars to .env.example Web: - lib/storage.ts: presign() utility and uploadToR2() direct-to-R2 PUT - lib/useUpload.ts: useUpload() hook (isUploading, publicUrl, error, upload) Mobile: - storage/UploadRepository.kt: UploadRepository interface + R2UploadRepository (injectable OkHttpClient, coroutine-safe, Result<String> return); add okhttp-mockwebserver test dependency Docs: - Create backend/docs/storage.md, web/docs/storage.md, mobile/docs/storage.md - Update environment.md, bootstrap.md, and three stale docs (error-handling.md, routing.md, websocket.md) Closes #22 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Warning Review limit reached
More reviews will be available in 21 minutes and 10 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more credits in the billing tab to continue. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (33)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
POST /api/v1/storage/presignandDELETE /api/v1/storage/:key— both Firebase-auth-protected and gated onR2_ACCOUNT_IDbeing setuseUpload()hook on web for presign → direct-to-R2 PUT flowR2UploadRepositoryon Android using OkHttp with injectable client for testingChanges by layer
Backend
usecase/storage.go—StorageServiceinterface at the correct Clean Architecture layerinfrastructure/storage/r2/storage.go— updated to returnusecase.StorageService; addsNewWithHTTPClientfor test injectionApp.StorageService, R2Configfields, optional init block.env.exampleupdated withR2_ACCOUNT_ID,R2_ACCESS_KEY,R2_SECRET_KEY,R2_BUCKET,R2_PUBLIC_URLWeb
lib/storage.ts—presign()anduploadToR2()utilitieslib/useUpload.ts—useUpload()hook withisUploading,publicUrl,error,uploadMobile
storage/UploadRepository.kt—UploadRepositoryinterface +R2UploadRepositoryimplokhttp-mockwebserveradded astestImplementationDocs
backend/docs/storage.md,web/docs/storage.md,mobile/docs/storage.mdenvironment.md,bootstrap.mderror-handling.md,routing.md,websocket.mdTest plan
go test ./internal/transport/handlers/... ./internal/infrastructure/storage/...— handler unit tests + R2 package tests (custom RoundTripper mock)pnpm test— 40 tests pass including 13 new storage/useUpload tests.\gradlew.bat test—UploadRepositoryTestpasses with MockWebServerPOST /api/v1/storage/presign, upload a file to the returned URL, verify it appears at the public URLDELETE /api/v1/storage/:key, verify the object is removedCloses #22