refactor: Flatten directory structure

Move project files from uzdb/ subdirectory to root directory for cleaner project structure.

Changes:
- Move frontend/ to root
- Move internal/ to root
- Move build/ to root
- Move all config files (go.mod, wails.json, etc.) to root
- Remove redundant uzdb/ subdirectory nesting

Project structure is now:
├── frontend/        # React application
├── internal/        # Go backend
├── build/           # Wails build assets
├── doc/             # Design documentation
├── main.go          # Entry point
└── ...

🤖 Generated with Qoder
This commit is contained in:
loveuer
2026-04-04 07:14:00 -07:00
parent 5a83e86bc9
commit 9874561410
83 changed files with 0 additions and 46 deletions

136
internal/utils/errors.go Normal file
View File

@@ -0,0 +1,136 @@
package utils
import (
"crypto/rand"
"encoding/base64"
"encoding/hex"
"fmt"
"strings"
"time"
)
// GenerateID generates a unique ID (UUID-like)
func GenerateID() string {
b := make([]byte, 16)
rand.Read(b)
return formatUUID(b)
}
// formatUUID formats bytes as UUID string
func formatUUID(b []byte) string {
uuid := make([]byte, 36)
hex.Encode(uuid[0:8], b[0:4])
hex.Encode(uuid[9:13], b[4:6])
hex.Encode(uuid[14:18], b[6:8])
hex.Encode(uuid[19:23], b[8:10])
hex.Encode(uuid[24:], b[10:])
uuid[8] = '-'
uuid[13] = '-'
uuid[18] = '-'
uuid[23] = '-'
return string(uuid)
}
// FormatDuration formats duration in milliseconds
func FormatDuration(d time.Duration) int64 {
return d.Milliseconds()
}
// SanitizeSQL removes potentially dangerous SQL patterns
// Note: This is not a replacement for parameterized queries
func SanitizeSQL(sql string) string {
// Remove multiple semicolons
sql = strings.ReplaceAll(sql, ";;", ";")
// Trim whitespace
sql = strings.TrimSpace(sql)
return sql
}
// TruncateString truncates a string to max length
func TruncateString(s string, maxLen int) string {
if len(s) <= maxLen {
return s
}
return s[:maxLen]
}
// GenerateRandomBytes generates random bytes
func GenerateRandomBytes(n int) ([]byte, error) {
b := make([]byte, n)
_, err := rand.Read(b)
if err != nil {
return nil, fmt.Errorf("failed to generate random bytes: %w", err)
}
return b, nil
}
// EncodeBase64 encodes bytes to base64 string
func EncodeBase64(data []byte) string {
return base64.StdEncoding.EncodeToString(data)
}
// DecodeBase64 decodes base64 string to bytes
func DecodeBase64(s string) ([]byte, error) {
return base64.StdEncoding.DecodeString(s)
}
// MaskPassword masks password for logging
func MaskPassword(password string) string {
if len(password) <= 4 {
return strings.Repeat("*", len(password))
}
return password[:2] + strings.Repeat("*", len(password)-2)
}
// ContainsAny checks if string contains any of the substrings
func ContainsAny(s string, substrings ...string) bool {
for _, sub := range substrings {
if strings.Contains(s, sub) {
return true
}
}
return false
}
// IsReadOnlyQuery checks if SQL query is read-only
func IsReadOnlyQuery(sql string) bool {
sql = strings.TrimSpace(strings.ToUpper(sql))
// Read-only operations
readOnlyPrefixes := []string{
"SELECT",
"SHOW",
"DESCRIBE",
"EXPLAIN",
"WITH",
}
for _, prefix := range readOnlyPrefixes {
if strings.HasPrefix(sql, prefix) {
return true
}
}
return false
}
// IsDDLQuery checks if SQL query is DDL
func IsDDLQuery(sql string) bool {
sql = strings.TrimSpace(strings.ToUpper(sql))
ddlKeywords := []string{
"CREATE",
"ALTER",
"DROP",
"TRUNCATE",
"RENAME",
}
for _, keyword := range ddlKeywords {
if strings.HasPrefix(sql, keyword) {
return true
}
}
return false
}