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"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/rede5/gohorsejobs/backend/internal/infrastructure/storage"
|
"github.com/rede5/gohorsejobs/backend/internal/infrastructure/storage"
|
||||||
|
"github.com/rede5/gohorsejobs/backend/internal/utils/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StorageHandler handles file storage operations
|
// StorageHandler handles file storage operations
|
||||||
|
|
@ -111,7 +111,7 @@ func (h *StorageHandler) GenerateUploadURL(w http.ResponseWriter, r *http.Reques
|
||||||
|
|
||||||
// Generate unique key
|
// Generate unique key
|
||||||
ext := filepath.Ext(req.Filename)
|
ext := filepath.Ext(req.Filename)
|
||||||
uniqueID := uuid.New().String()
|
uniqueID := uuid.V7()
|
||||||
timestamp := time.Now().Format("20060102")
|
timestamp := time.Now().Format("20060102")
|
||||||
key := fmt.Sprintf("%s/%s/%s%s", folder, timestamp, uniqueID, ext)
|
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 (
|
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,
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
type VARCHAR(50) NOT NULL, -- info, success, warning, error
|
type VARCHAR(50) NOT NULL, -- info, success, warning, error
|
||||||
title VARCHAR(255) NOT NULL,
|
title VARCHAR(255) NOT NULL,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ DROP TABLE IF EXISTS ticket_messages;
|
||||||
DROP TABLE IF EXISTS tickets;
|
DROP TABLE IF EXISTS tickets;
|
||||||
|
|
||||||
CREATE TABLE 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,
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
subject VARCHAR(255) NOT NULL,
|
subject VARCHAR(255) NOT NULL,
|
||||||
status VARCHAR(50) NOT NULL DEFAULT 'open', -- open, in_progress, closed
|
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 INDEX idx_tickets_status ON tickets(status);
|
||||||
|
|
||||||
CREATE TABLE ticket_messages (
|
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,
|
ticket_id UUID NOT NULL REFERENCES tickets(id) ON DELETE CASCADE,
|
||||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, -- Sender
|
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, -- Sender
|
||||||
message TEXT NOT NULL,
|
message TEXT NOT NULL,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
-- Description: Track payments for job postings
|
-- Description: Track payments for job postings
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS job_payments (
|
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,
|
job_id INT NOT NULL,
|
||||||
user_id INT,
|
user_id INT,
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue