refactor: clean up legacy UUID v4, use UUID v7 everywhere
Migrations: - 016, 017, 019: Replace gen_random_uuid() with uuid_generate_v7() - All UUID tables now use custom uuid_generate_v7() function Backend: - Create internal/utils/uuid/uuid.go with V7() function (RFC 9562) - Update storage_handler.go to use internal uuid.V7() - Remove dependency on google/uuid for file naming All new UUIDs in the system are now UUID v7 (time-ordered)
This commit is contained in:
parent
7f30a214f7
commit
568b4ebb88
5 changed files with 70 additions and 6 deletions
|
|
@ -8,8 +8,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/rede5/gohorsejobs/backend/internal/infrastructure/storage"
|
||||
"github.com/rede5/gohorsejobs/backend/internal/utils/uuid"
|
||||
)
|
||||
|
||||
// StorageHandler handles file storage operations
|
||||
|
|
@ -111,7 +111,7 @@ func (h *StorageHandler) GenerateUploadURL(w http.ResponseWriter, r *http.Reques
|
|||
|
||||
// Generate unique key
|
||||
ext := filepath.Ext(req.Filename)
|
||||
uniqueID := uuid.New().String()
|
||||
uniqueID := uuid.V7()
|
||||
timestamp := time.Now().Format("20060102")
|
||||
key := fmt.Sprintf("%s/%s/%s%s", folder, timestamp, uniqueID, ext)
|
||||
|
||||
|
|
|
|||
64
backend/internal/utils/uuid/uuid.go
Normal file
64
backend/internal/utils/uuid/uuid.go
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
package uuid
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// V7 generates a UUID v7 (time-ordered) following RFC 9562
|
||||
// Format: tttttttt-tttt-7xxx-yxxx-xxxxxxxxxxxx
|
||||
// Where: t = timestamp (48 bits), 7 = version, y = variant, x = random
|
||||
func V7() string {
|
||||
// Get current timestamp in milliseconds
|
||||
timestamp := time.Now().UnixMilli()
|
||||
|
||||
// Generate 10 random bytes
|
||||
randomBytes := make([]byte, 10)
|
||||
rand.Read(randomBytes)
|
||||
|
||||
// Build UUID bytes (16 total)
|
||||
var bytes [16]byte
|
||||
|
||||
// First 6 bytes: timestamp (48 bits, big-endian)
|
||||
binary.BigEndian.PutUint32(bytes[0:4], uint32(timestamp>>16))
|
||||
binary.BigEndian.PutUint16(bytes[4:6], uint16(timestamp))
|
||||
|
||||
// Next 2 bytes: version (4 bits = 7) + random (12 bits)
|
||||
bytes[6] = 0x70 | (randomBytes[0] & 0x0F) // version 7
|
||||
bytes[7] = randomBytes[1]
|
||||
|
||||
// Last 8 bytes: variant (2 bits = 10) + random (62 bits)
|
||||
bytes[8] = 0x80 | (randomBytes[2] & 0x3F) // variant RFC 4122
|
||||
copy(bytes[9:16], randomBytes[3:10])
|
||||
|
||||
// Format as UUID string
|
||||
return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x",
|
||||
binary.BigEndian.Uint32(bytes[0:4]),
|
||||
binary.BigEndian.Uint16(bytes[4:6]),
|
||||
binary.BigEndian.Uint16(bytes[6:8]),
|
||||
binary.BigEndian.Uint16(bytes[8:10]),
|
||||
bytes[10:16],
|
||||
)
|
||||
}
|
||||
|
||||
// IsValid checks if a string is a valid UUID (any version)
|
||||
func IsValid(s string) bool {
|
||||
// Basic UUID format check: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if len(s) != 36 {
|
||||
return false
|
||||
}
|
||||
for i, c := range s {
|
||||
if i == 8 || i == 13 || i == 18 || i == 23 {
|
||||
if c != '-' {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
CREATE TABLE IF NOT EXISTS notifications (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
type VARCHAR(50) NOT NULL, -- info, success, warning, error
|
||||
title VARCHAR(255) NOT NULL,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ DROP TABLE IF EXISTS ticket_messages;
|
|||
DROP TABLE IF EXISTS tickets;
|
||||
|
||||
CREATE TABLE tickets (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
subject VARCHAR(255) NOT NULL,
|
||||
status VARCHAR(50) NOT NULL DEFAULT 'open', -- open, in_progress, closed
|
||||
|
|
@ -15,7 +15,7 @@ CREATE INDEX idx_tickets_user_id ON tickets(user_id);
|
|||
CREATE INDEX idx_tickets_status ON tickets(status);
|
||||
|
||||
CREATE TABLE ticket_messages (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
|
||||
ticket_id UUID NOT NULL REFERENCES tickets(id) ON DELETE CASCADE,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, -- Sender
|
||||
message TEXT NOT NULL,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
-- Description: Track payments for job postings
|
||||
|
||||
CREATE TABLE IF NOT EXISTS job_payments (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
|
||||
job_id INT NOT NULL,
|
||||
user_id INT,
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue