# Gitea Architecture Review & Suggestions **Reviewer:** Senior Architect **Date:** January 2026 **Scope:** Full codebase review with focus on API, services, and recent chunked upload implementation --- ## Executive Summary Gitea demonstrates a **well-designed, pragmatic architecture** suitable for a mature self-hosted Git platform. The codebase follows clean layered patterns (routers → services → models) with good separation of concerns. However, there are opportunities to improve **operational observability**, **reliability**, **developer experience**, and **AI/automation friendliness**. This document presents findings organized by priority and effort level. --- ## Table of Contents 1. [Chunked Upload Implementation Review](#1-chunked-upload-implementation-review) 2. [API Design Improvements](#2-api-design-improvements) 3. [Error Handling & Observability](#3-error-handling--observability) 4. [Reliability & Resilience](#4-reliability--resilience) 5. [Developer Experience](#5-developer-experience) 6. [AI & Automation Friendliness](#6-ai--automation-friendliness) 7. [Security Considerations](#7-security-considerations) 8. [Performance Optimizations](#8-performance-optimizations) 9. [Implementation Roadmap](#9-implementation-roadmap) --- ## 1. Chunked Upload Implementation Review ### What Was Done Well - Clean separation: model (`upload_session.go`), service (`chunked.go`), handler (`upload.go`) - Resumable uploads with session status tracking - Automatic cleanup via cron job - Follows existing Gitea patterns for API handlers and models ### Issues to Address #### 1.1 Missing Chunk Verification (HIGH) **Problem:** No checksum verification for uploaded chunks. Corrupted chunks will produce corrupted files. **Suggestion:** ```go // Add to UploadSession model type UploadSession struct { // ... existing fields ChecksumAlgorithm string `xorm:"DEFAULT 'sha256'"` // sha256, md5, none ExpectedChecksum string `xorm:""` // Full file checksum } // Add to chunk upload type ChunkMetadata struct { ChunkNumber int64 `json:"chunk_number"` Checksum string `json:"checksum"` // Chunk checksum Size int64 `json:"size"` } ``` #### 1.2 No Concurrent Upload Protection (MEDIUM) **Problem:** Same chunk can be uploaded multiple times concurrently, causing race conditions. **Suggestion:** ```go // Add file locking or atomic operations func SaveChunk(ctx context.Context, session *UploadSession, chunkNum int64, ...) error { lockPath := session.GetChunkPath(chunkNum) + ".lock" lock, err := acquireFileLock(lockPath) if err != nil { return fmt.Errorf("chunk %d is being uploaded by another request", chunkNum) } defer lock.Release() // ... save chunk } ``` #### 1.3 Missing Progress Webhook (MEDIUM) **Problem:** No way to notify external systems of upload progress. **Suggestion:** ```go // Emit webhook on upload milestones if session.ChunksReceived % 10 == 0 || session.IsComplete() { notify_service.UploadProgress(ctx, session) } ``` #### 1.4 No Rate Limiting (MEDIUM) **Problem:** Unlimited chunk uploads could exhaust server resources. **Suggestion:** ```go // Add rate limiting middleware for upload endpoints m.Group("/uploads", func() { // ... routes }, rateLimit(100, time.Minute)) // 100 chunks per minute per user ``` #### 1.5 Temp File Cleanup on Failure (LOW) **Problem:** If `AssembleChunks` fails partway through, temp files may not be cleaned up. **Suggestion:** ```go func AssembleChunks(...) (*Attachment, error) { defer func() { if r := recover(); r != nil { cleanupTempFiles(session) panic(r) } }() // ... existing logic } ``` --- ## 2. API Design Improvements ### 2.1 Standardized Error Response Format (HIGH) **Current State:** Error responses vary in format across endpoints. **Suggestion:** Adopt RFC 7807 Problem Details format: ```go // modules/structs/error.go type APIError struct { Type string `json:"type"` // URI reference Title string `json:"title"` // Short summary Status int `json:"status"` // HTTP status code Detail string `json:"detail"` // Explanation Instance string `json:"instance,omitempty"` // Request URI Code string `json:"code"` // Machine-readable code Errors []ValidationError `json:"errors,omitempty"` // Field-level errors } // Example response: { "type": "https://gitea.io/errors/validation", "title": "Validation Failed", "status": 422, "detail": "The provided repository name is invalid", "code": "ERR_VALIDATION_FAILED", "errors": [ {"field": "name", "message": "must be alphanumeric", "code": "ERR_INVALID_CHARS"} ] } ``` ### 2.2 Batch Operations API (HIGH) **Current State:** No batch endpoints for bulk operations. **Suggestion:** Add batch endpoints for common operations: ``` POST /api/v1/repos/{owner}/{repo}/issues/batch POST /api/v1/repos/{owner}/{repo}/labels/batch POST /api/v1/admin/users/batch ``` ```go // Example batch request { "operations": [ {"action": "close", "issue_ids": [1, 2, 3]}, {"action": "add_label", "issue_ids": [1, 2], "label_id": 5} ] } // Example batch response { "results": [ {"index": 0, "success": true, "affected": 3}, {"index": 1, "success": false, "error": {"code": "ERR_NOT_FOUND", "detail": "Label 5 not found"}} ], "summary": {"total": 2, "succeeded": 1, "failed": 1} } ``` ### 2.3 Cursor-Based Pagination (MEDIUM) **Current State:** Offset-based pagination can be slow for large datasets. **Suggestion:** Add cursor-based pagination option: ``` GET /api/v1/repos/{owner}/{repo}/issues?cursor=eyJpZCI6MTAwfQ&limit=50 ``` ```go type PaginatedResponse struct { Data []any `json:"data"` NextCursor string `json:"next_cursor,omitempty"` PrevCursor string `json:"prev_cursor,omitempty"` HasMore bool `json:"has_more"` Total int64 `json:"total,omitempty"` // Optional, expensive to compute } ``` ### 2.4 Field Selection (GraphQL-lite) (MEDIUM) **Current State:** All fields returned on every request. **Suggestion:** Add field selection parameter: ``` GET /api/v1/repos/{owner}/{repo}?fields=id,name,description,stars_count ``` ```go // Reduces payload and database load func filterFields(obj any, fields []string) map[string]any { // Return only requested fields } ``` ### 2.5 API Versioning Header (LOW) **Current State:** No API version negotiation. **Suggestion:** Add version header support: ``` Accept: application/vnd.gitea.v2+json X-Gitea-API-Version: 2 ``` --- ## 3. Error Handling & Observability ### 3.1 Centralized Error Catalog (HIGH) **Current State:** 100+ custom error types scattered across packages. **Suggestion:** Create centralized error registry: ```go // modules/errors/catalog.go package errors type ErrorCode string const ( // Authentication errors (1xxx) ErrAuthRequired ErrorCode = "ERR_1001" ErrInvalidToken ErrorCode = "ERR_1002" ErrTokenExpired ErrorCode = "ERR_1003" // Authorization errors (2xxx) ErrForbidden ErrorCode = "ERR_2001" ErrNotRepoMember ErrorCode = "ERR_2002" // Resource errors (3xxx) ErrUserNotFound ErrorCode = "ERR_3001" ErrRepoNotFound ErrorCode = "ERR_3002" ErrIssueNotFound ErrorCode = "ERR_3003" // Validation errors (4xxx) ErrInvalidInput ErrorCode = "ERR_4001" ErrNameTooLong ErrorCode = "ERR_4002" // Upload errors (5xxx) ErrUploadSessionExpired ErrorCode = "ERR_5001" ErrChunkMissing ErrorCode = "ERR_5002" ErrFileTooLarge ErrorCode = "ERR_5003" ) var errorMessages = map[ErrorCode]string{ ErrAuthRequired: "Authentication required", ErrInvalidToken: "Invalid or malformed token", // ... } func (e ErrorCode) Error() string { return errorMessages[e] } func (e ErrorCode) HTTPStatus() int { /* return appropriate status */ } ``` ### 3.2 Request Tracing (HIGH) **Current State:** No correlation IDs for request tracing. **Suggestion:** Add OpenTelemetry integration: ```go // modules/web/middleware/tracing.go func TracingMiddleware() func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { traceID := r.Header.Get("X-Request-ID") if traceID == "" { traceID = uuid.New().String() } ctx := context.WithValue(r.Context(), TraceIDKey, traceID) w.Header().Set("X-Request-ID", traceID) // Add to structured logging log := log.WithField("trace_id", traceID) ctx = context.WithValue(ctx, LoggerKey, log) next.ServeHTTP(w, r.WithContext(ctx)) }) } } ``` ### 3.3 Structured Logging (MEDIUM) **Current State:** Mix of structured and unstructured logging. **Suggestion:** Standardize on JSON structured logs: ```go // All log entries should include: { "timestamp": "2024-01-08T12:00:00Z", "level": "info", "trace_id": "abc-123", "user_id": 42, "repo_id": 100, "action": "create_issue", "duration_ms": 45, "message": "Issue created successfully" } ``` ### 3.4 Metrics Endpoint Enhancement (MEDIUM) **Current State:** Basic Prometheus metrics. **Suggestion:** Add business metrics: ```go // Metrics to add: gitea_api_requests_total{method, endpoint, status} gitea_api_request_duration_seconds{method, endpoint} gitea_upload_sessions_active gitea_upload_bytes_total gitea_webhook_deliveries_total{status, hook_type} gitea_webhook_delivery_duration_seconds gitea_repository_operations_total{operation} ``` --- ## 4. Reliability & Resilience ### 4.1 Webhook Retry with Exponential Backoff (HIGH) **Current State:** Limited retry logic visible. **Suggestion:** ```go // services/webhook/deliver.go type RetryConfig struct { MaxRetries int // Default: 5 InitialBackoff time.Duration // Default: 1s MaxBackoff time.Duration // Default: 5m BackoffFactor float64 // Default: 2.0 } func DeliverWithRetry(ctx context.Context, task *HookTask, cfg RetryConfig) error { var lastErr error backoff := cfg.InitialBackoff for attempt := 0; attempt <= cfg.MaxRetries; attempt++ { err := Deliver(ctx, task) if err == nil { return nil } lastErr = err // Log retry log.Warn("Webhook delivery failed, retrying", "task_id", task.ID, "attempt", attempt+1, "next_backoff", backoff) select { case <-ctx.Done(): return ctx.Err() case <-time.After(backoff): } backoff = time.Duration(float64(backoff) * cfg.BackoffFactor) if backoff > cfg.MaxBackoff { backoff = cfg.MaxBackoff } } // Move to dead letter queue if err := moveToDeadLetterQueue(ctx, task, lastErr); err != nil { log.Error("Failed to move to DLQ", "task_id", task.ID, "error", err) } return fmt.Errorf("webhook delivery failed after %d attempts: %w", cfg.MaxRetries, lastErr) } ``` ### 4.2 Circuit Breaker for External Services (MEDIUM) **Current State:** No circuit breaker pattern. **Suggestion:** ```go // modules/circuitbreaker/breaker.go type CircuitBreaker struct { name string maxFailures int resetTimeout time.Duration state State // Closed, Open, HalfOpen failures int lastFailure time.Time } func (cb *CircuitBreaker) Execute(fn func() error) error { if cb.state == Open { if time.Since(cb.lastFailure) > cb.resetTimeout { cb.state = HalfOpen } else { return ErrCircuitOpen } } err := fn() if err != nil { cb.recordFailure() return err } cb.recordSuccess() return nil } // Usage for webhook delivery, OAuth providers, etc. var webhookBreaker = NewCircuitBreaker("webhook", 5, time.Minute) ``` ### 4.3 Graceful Degradation (MEDIUM) **Current State:** Services fail hard on dependency failures. **Suggestion:** Add fallback behaviors: ```go // Example: Search indexer fallback func SearchIssues(ctx context.Context, query string) ([]Issue, error) { if indexer.IsHealthy() { return indexer.Search(ctx, query) } // Fallback to database search (slower but works) log.Warn("Search indexer unavailable, falling back to DB search") return db.SearchIssuesByTitle(ctx, query) } ``` ### 4.4 Health Check Endpoints (LOW) **Current State:** Basic health check. **Suggestion:** Add detailed health checks: ``` GET /api/v1/health GET /api/v1/health/live # Kubernetes liveness GET /api/v1/health/ready # Kubernetes readiness ``` ```json { "status": "healthy", "version": "1.24.0", "checks": { "database": {"status": "up", "latency_ms": 2}, "redis": {"status": "up", "latency_ms": 1}, "search_indexer": {"status": "degraded", "message": "High latency"}, "storage": {"status": "up", "free_space_gb": 450} } } ``` --- ## 5. Developer Experience ### 5.1 OpenAPI Spec Improvements (HIGH) **Current State:** Swagger docs generated from code comments. **Suggestion:** Enhance with examples and better descriptions: ```go // swagger:operation POST /repos/{owner}/{repo}/issues repository createIssue // --- // summary: Create an issue // description: | // Creates a new issue in the repository. The authenticated user must have // write access to the repository. // // ## Example // ```json // {"title": "Bug report", "body": "Description here", "labels": [1, 2]} // ``` // consumes: // - application/json // produces: // - application/json // parameters: // - name: body // in: body // schema: // "$ref": "#/definitions/CreateIssueOption" // example: // title: "Bug: Login fails" // body: "When I try to login..." // labels: [1, 2] // responses: // "201": // description: Issue created // schema: // "$ref": "#/definitions/Issue" // examples: // application/json: // id: 1 // title: "Bug: Login fails" // state: "open" ``` ### 5.2 SDK Generation (MEDIUM) **Current State:** No official SDK libraries. **Suggestion:** Generate SDKs from OpenAPI spec: ```bash # Generate SDKs openapi-generator generate -i api/v1/swagger.json -g python -o sdk/python openapi-generator generate -i api/v1/swagger.json -g typescript-axios -o sdk/typescript openapi-generator generate -i api/v1/swagger.json -g go -o sdk/go ``` ### 5.3 CLI Tool Enhancement (MEDIUM) **Current State:** Basic CLI for Git operations. **Suggestion:** Add API CLI tool: ```bash # Proposed gitea-cli commands gitea-cli auth login --server https://gitea.example.com gitea-cli repo list gitea-cli repo create myrepo --private gitea-cli issue create --title "Bug" --body "Description" gitea-cli release create v1.0.0 --attach ./binary.zip gitea-cli upload --chunked ./large-file.zip # Uses chunked upload ``` ### 5.4 Webhook Debugging Tools (LOW) **Current State:** Limited visibility into webhook delivery. **Suggestion:** Add webhook inspection endpoints: ``` GET /api/v1/repos/{owner}/{repo}/hooks/{id}/deliveries GET /api/v1/repos/{owner}/{repo}/hooks/{id}/deliveries/{delivery_id} POST /api/v1/repos/{owner}/{repo}/hooks/{id}/deliveries/{delivery_id}/redeliver ``` --- ## 6. AI & Automation Friendliness ### 6.1 Machine-Readable Error Codes (HIGH) **Current State:** Error messages are human-readable strings. **Suggestion:** Always include machine-readable codes: ```json { "code": "ERR_REPO_ARCHIVED", "message": "Repository is archived and cannot be modified", "documentation_url": "https://docs.gitea.io/errors/ERR_REPO_ARCHIVED" } ``` ### 6.2 Idempotency Keys (HIGH) **Current State:** No idempotency support for POST requests. **Suggestion:** Add idempotency key header: ```go // Header: Idempotency-Key: func IdempotencyMiddleware() func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" && r.Method != "PUT" { next.ServeHTTP(w, r) return } key := r.Header.Get("Idempotency-Key") if key == "" { next.ServeHTTP(w, r) return } // Check cache if cached, found := idempotencyCache.Get(key); found { w.Header().Set("X-Idempotency-Replayed", "true") writeResponse(w, cached) return } // Capture response rec := httptest.NewRecorder() next.ServeHTTP(rec, r) // Cache successful responses if rec.Code >= 200 && rec.Code < 300 { idempotencyCache.Set(key, rec, 24*time.Hour) } copyResponse(w, rec) }) } } ``` ### 6.3 Webhook Event Catalog (MEDIUM) **Current State:** Events documented but not discoverable via API. **Suggestion:** Add event discovery endpoint: ``` GET /api/v1/events ``` ```json { "events": [ { "name": "push", "description": "Triggered when commits are pushed", "payload_schema": {"$ref": "#/definitions/PushPayload"}, "example": {...} }, { "name": "issues", "description": "Triggered for issue events", "actions": ["opened", "closed", "edited", "labeled"], "payload_schema": {"$ref": "#/definitions/IssuePayload"} } ] } ``` ### 6.4 Async Operation Pattern (MEDIUM) **Current State:** Long operations block HTTP requests. **Suggestion:** Add async operation pattern for long-running tasks: ``` POST /api/v1/repos/{owner}/{repo}/mirror-sync Response: 202 Accepted { "operation_id": "op_abc123", "status": "pending", "status_url": "/api/v1/operations/op_abc123", "estimated_completion": "2024-01-08T12:05:00Z" } GET /api/v1/operations/op_abc123 { "operation_id": "op_abc123", "status": "running", "progress": 45, "started_at": "2024-01-08T12:00:00Z" } ``` ### 6.5 Rate Limit Headers (MEDIUM) **Current State:** Limited rate limit visibility. **Suggestion:** Add standard rate limit headers: ``` X-RateLimit-Limit: 5000 X-RateLimit-Remaining: 4990 X-RateLimit-Reset: 1704720000 X-RateLimit-Resource: api ``` ### 6.6 Conditional Requests (LOW) **Current State:** Limited ETag/If-Match support. **Suggestion:** Add conditional request support: ``` GET /api/v1/repos/owner/repo Response Headers: ETag: "abc123" Last-Modified: Wed, 08 Jan 2024 12:00:00 GMT GET /api/v1/repos/owner/repo Request Headers: If-None-Match: "abc123" Response: 304 Not Modified PUT /api/v1/repos/owner/repo Request Headers: If-Match: "abc123" # Prevents lost updates ``` --- ## 7. Security Considerations ### 7.1 Audit Logging (HIGH) **Current State:** Limited audit trail. **Suggestion:** Add comprehensive audit logging: ```go type AuditEvent struct { ID int64 `json:"id"` Timestamp time.Time `json:"timestamp"` ActorID int64 `json:"actor_id"` ActorIP string `json:"actor_ip"` Action string `json:"action"` // "repo.create", "user.delete" Resource string `json:"resource"` // "repository", "user" ResourceID int64 `json:"resource_id"` OldValue string `json:"old_value,omitempty"` // JSON NewValue string `json:"new_value,omitempty"` // JSON UserAgent string `json:"user_agent"` TraceID string `json:"trace_id"` } // Store in separate audit_log table // Expose via admin API: GET /api/v1/admin/audit-log ``` ### 7.2 Token Scopes Enhancement (MEDIUM) **Current State:** Basic token scopes. **Suggestion:** Add granular scopes: ``` repo:read # Read repository data repo:write # Push to repository repo:delete # Delete repository issues:read # Read issues issues:write # Create/edit issues releases:read # Read releases releases:write # Create releases releases:upload # Upload release assets (for CI) admin:users # Manage users admin:repos # Manage all repos webhook:manage # Manage webhooks ``` ### 7.3 Request Signing (LOW) **Current State:** Token-based auth only. **Suggestion:** Add HMAC request signing for webhooks: ```go // For high-security integrations signature := hmac.New(sha256.New, []byte(secret)) signature.Write([]byte(timestamp + "." + requestBody)) expectedSig := hex.EncodeToString(signature.Sum(nil)) // Header: X-Gitea-Signature: sha256= // Header: X-Gitea-Timestamp: ``` --- ## 8. Performance Optimizations ### 8.1 Response Compression (HIGH) **Current State:** Gzip available but not always used. **Suggestion:** Ensure compression for all JSON responses: ```go // Middleware to compress responses > 1KB func CompressionMiddleware(next http.Handler) http.Handler { return gziphandler.GzipHandler(next) } ``` ### 8.2 Database Query Optimization (MEDIUM) **Current State:** Some N+1 query patterns. **Suggestion:** Add eager loading for common associations: ```go // Instead of loading issues then loading users one by one issues, _ := GetIssues(ctx, opts) for _, issue := range issues { issue.Poster, _ = GetUser(issue.PosterID) // N+1! } // Use eager loading issues, _ := GetIssuesWithUsers(ctx, opts) // Single JOIN query ``` ### 8.3 Caching Layer (MEDIUM) **Current State:** Limited caching. **Suggestion:** Add Redis/memory caching for hot paths: ```go // Cache frequently accessed data func GetRepository(ctx context.Context, id int64) (*Repository, error) { cacheKey := fmt.Sprintf("repo:%d", id) if cached, found := cache.Get(cacheKey); found { return cached.(*Repository), nil } repo, err := db.GetRepository(ctx, id) if err != nil { return nil, err } cache.Set(cacheKey, repo, 5*time.Minute) return repo, nil } ``` ### 8.4 Connection Pooling Tuning (LOW) **Current State:** Default connection pool settings. **Suggestion:** Add configurable pool settings: ```ini [database] MAX_OPEN_CONNS = 100 MAX_IDLE_CONNS = 10 CONN_MAX_LIFETIME = 1h CONN_MAX_IDLE_TIME = 10m ``` --- ## 9. Implementation Roadmap ### Phase 1: Quick Wins (1-2 weeks) | Item | Priority | Effort | Impact | |------|----------|--------|--------| | Add request tracing (X-Request-ID) | HIGH | Low | High | | Add rate limit headers | MEDIUM | Low | Medium | | Add chunk checksum verification | HIGH | Low | High | | Standardize error response format | HIGH | Medium | High | ### Phase 2: Foundation (2-4 weeks) | Item | Priority | Effort | Impact | |------|----------|--------|--------| | Centralized error catalog | HIGH | Medium | High | | Webhook retry with backoff | HIGH | Medium | High | | Idempotency key support | HIGH | Medium | High | | Audit logging | HIGH | Medium | High | | Health check endpoints | LOW | Low | Medium | ### Phase 3: Enhancement (4-8 weeks) | Item | Priority | Effort | Impact | |------|----------|--------|--------| | Batch operations API | HIGH | High | High | | Cursor-based pagination | MEDIUM | Medium | Medium | | SDK generation pipeline | MEDIUM | Medium | Medium | | Circuit breaker pattern | MEDIUM | Medium | Medium | | Event discovery endpoint | MEDIUM | Low | Medium | ### Phase 4: Advanced (8+ weeks) | Item | Priority | Effort | Impact | |------|----------|--------|--------| | Async operation pattern | MEDIUM | High | Medium | | Field selection (GraphQL-lite) | MEDIUM | High | Medium | | API versioning | LOW | High | Low | | Full OpenTelemetry integration | MEDIUM | High | High | --- ## Appendix A: Chunked Upload Quick Fixes ```go // 1. Add checksum to chunk upload (upload.go) func UploadChunk(ctx *context.APIContext) { // Get expected checksum from header expectedChecksum := ctx.Req.Header.Get("X-Chunk-Checksum") // ... save chunk ... // Verify checksum if provided if expectedChecksum != "" { actualChecksum := sha256sum(chunkData) if actualChecksum != expectedChecksum { ctx.APIError(http.StatusBadRequest, api.APIError{ Code: "ERR_CHECKSUM_MISMATCH", Detail: "Chunk checksum verification failed", }) return } } } // 2. Add final file checksum verification (chunked.go) func AssembleChunks(...) (*Attachment, error) { // ... assemble chunks ... // Verify final checksum if expected if session.ExpectedChecksum != "" { actualChecksum := computeFileChecksum(finalPath) if actualChecksum != session.ExpectedChecksum { return nil, fmt.Errorf("file checksum mismatch: expected %s, got %s", session.ExpectedChecksum, actualChecksum) } } // ... create attachment ... } ``` --- ## Appendix B: Sample Error Catalog ```go // modules/errors/codes.go package errors // Error codes organized by category const ( // 1xxx - Authentication ErrCodeAuthRequired = "ERR_1001" ErrCodeInvalidToken = "ERR_1002" ErrCodeTokenExpired = "ERR_1003" ErrCodeInvalidPassword = "ERR_1004" ErrCode2FARequired = "ERR_1005" // 2xxx - Authorization ErrCodeForbidden = "ERR_2001" ErrCodeNotRepoMember = "ERR_2002" ErrCodeNotOrgMember = "ERR_2003" ErrCodeInsufficientPerm = "ERR_2004" // 3xxx - Resource Not Found ErrCodeUserNotFound = "ERR_3001" ErrCodeRepoNotFound = "ERR_3002" ErrCodeIssueNotFound = "ERR_3003" ErrCodeReleaseNotFound = "ERR_3004" ErrCodeBranchNotFound = "ERR_3005" // 4xxx - Validation ErrCodeInvalidInput = "ERR_4001" ErrCodeNameTooLong = "ERR_4002" ErrCodeInvalidEmail = "ERR_4003" ErrCodeDuplicateName = "ERR_4004" // 5xxx - Upload ErrCodeSessionExpired = "ERR_5001" ErrCodeChunkMissing = "ERR_5002" ErrCodeFileTooLarge = "ERR_5003" ErrCodeChecksumMismatch = "ERR_5004" ErrCodeInvalidFileType = "ERR_5005" // 6xxx - Rate Limiting ErrCodeRateLimited = "ERR_6001" ErrCodeTooManyRequests = "ERR_6002" // 7xxx - Server ErrCodeInternal = "ERR_7001" ErrCodeServiceDown = "ERR_7002" ErrCodeTimeout = "ERR_7003" ) ``` --- *Document prepared for discussion. All suggestions should be evaluated against project priorities and resource constraints.*