Files
ackify/backend/internal/presentation/api/shared/errors.go
Benjamin e95185f9c7 feat: migrate to Vue.js SPA with API-first architecture
Major refactoring to modernize the application architecture:

Backend changes:
- Restructure API with v1 versioning and modular handlers
- Add comprehensive OpenAPI specification
- Implement RESTful endpoints for documents, signatures, admin
- Add checksum verification system for document integrity
- Add server-side runtime injection of ACKIFY_BASE_URL and meta tags
- Generate dynamic Open Graph/Twitter Card meta tags for unfurling
- Remove legacy HTML template handlers
- Isolate backend source on dedicated folder
- Improve tests suite

Frontend changes:
- Migrate from Go templates to Vue.js 3 SPA with TypeScript
- Add Tailwind CSS with shadcn/vue components
- Implement i18n support (fr, en, es, de, it)
- Add admin dashboard for document and signer management
- Add signature tracking with file checksum verification
- Add embed page with sign button linking to main app
- Implement dark mode and accessibility features
- Auto load file to compute checksum

Infrastructure:
- Update Dockerfile for SPA build process
- Simplify deployment with embedded frontend assets
- Add migration for checksum_verifications table

This enables better UX, proper link previews on social platforms,
and provides a foundation for future enhancements.
2025-10-26 02:32:10 +02:00

102 lines
3.0 KiB
Go

// SPDX-License-Identifier: AGPL-3.0-or-later
package shared
import (
"encoding/json"
"net/http"
)
// ErrorCode represents standardized API error codes
type ErrorCode string
const (
// Client errors
ErrCodeValidation ErrorCode = "VALIDATION_ERROR"
ErrCodeBadRequest ErrorCode = "BAD_REQUEST"
ErrCodeUnauthorized ErrorCode = "UNAUTHORIZED"
ErrCodeForbidden ErrorCode = "FORBIDDEN"
ErrCodeNotFound ErrorCode = "NOT_FOUND"
ErrCodeConflict ErrorCode = "CONFLICT"
ErrCodeRateLimited ErrorCode = "RATE_LIMITED"
ErrCodeCSRFInvalid ErrorCode = "CSRF_INVALID"
// Server errors
ErrCodeInternal ErrorCode = "INTERNAL_ERROR"
ErrCodeServiceUnavailable ErrorCode = "SERVICE_UNAVAILABLE"
)
// ErrorResponse represents a standardized error response
type ErrorResponse struct {
Error ErrorDetail `json:"error"`
}
// ErrorDetail contains error details
type ErrorDetail struct {
Code ErrorCode `json:"code"`
Message string `json:"message"`
Details map[string]interface{} `json:"details,omitempty"`
}
// WriteError writes a standardized error response
func WriteError(w http.ResponseWriter, statusCode int, code ErrorCode, message string, details map[string]interface{}) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(statusCode)
response := ErrorResponse{
Error: ErrorDetail{
Code: code,
Message: message,
Details: details,
},
}
json.NewEncoder(w).Encode(response)
}
// WriteValidationError writes a validation error response
func WriteValidationError(w http.ResponseWriter, message string, fieldErrors map[string]string) {
details := make(map[string]interface{})
if fieldErrors != nil {
details["fields"] = fieldErrors
}
WriteError(w, http.StatusBadRequest, ErrCodeValidation, message, details)
}
// WriteUnauthorized writes an unauthorized error response
func WriteUnauthorized(w http.ResponseWriter, message string) {
if message == "" {
message = "Authentication required"
}
WriteError(w, http.StatusUnauthorized, ErrCodeUnauthorized, message, nil)
}
// WriteForbidden writes a forbidden error response
func WriteForbidden(w http.ResponseWriter, message string) {
if message == "" {
message = "Access denied"
}
WriteError(w, http.StatusForbidden, ErrCodeForbidden, message, nil)
}
// WriteNotFound writes a not found error response
func WriteNotFound(w http.ResponseWriter, resource string) {
message := "Resource not found"
if resource != "" {
message = resource + " not found"
}
WriteError(w, http.StatusNotFound, ErrCodeNotFound, message, nil)
}
// WriteConflict writes a conflict error response
func WriteConflict(w http.ResponseWriter, message string) {
if message == "" {
message = "Resource conflict"
}
WriteError(w, http.StatusConflict, ErrCodeConflict, message, nil)
}
// WriteInternalError writes an internal server error response
func WriteInternalError(w http.ResponseWriter) {
WriteError(w, http.StatusInternalServerError, ErrCodeInternal, "An internal error occurred", nil)
}