feat: replace UUID v4 with UUID v7 across backend
Define uuid_generate_v7() in the first migration and switch all table primary key defaults to it. Remove the uuid-ossp extension dependency. Update refresh token and request ID generation in Go code to use uuid.NewV7() from the existing google/uuid v1.6.0 library. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,35 @@
|
||||
-- +goose Up
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
|
||||
-- Generate UUID v7 (time-ordered, millisecond precision).
|
||||
-- Structure: 48-bit unix_ts_ms | 4-bit version (0111) | 12-bit rand_a | 2-bit variant (10) | 62-bit rand_b
|
||||
CREATE OR REPLACE FUNCTION uuid_generate_v7()
|
||||
RETURNS uuid
|
||||
AS $$
|
||||
DECLARE
|
||||
unix_ts_ms bytea;
|
||||
uuid_bytes bytea;
|
||||
BEGIN
|
||||
-- 48-bit Unix timestamp in milliseconds.
|
||||
-- int8send produces 8 big-endian bytes; skip the first 2 zero bytes to get 6.
|
||||
unix_ts_ms = substring(int8send(floor(extract(epoch from clock_timestamp()) * 1000)::bigint) from 3);
|
||||
|
||||
-- Use a random v4 UUID as the source of random bits for rand_a and rand_b.
|
||||
uuid_bytes = uuid_send(gen_random_uuid());
|
||||
|
||||
-- Overwrite bytes 0–5 with the timestamp (positions 1–6 in 1-indexed bytea).
|
||||
uuid_bytes = overlay(uuid_bytes placing unix_ts_ms from 1 for 6);
|
||||
|
||||
-- Set version nibble (bits 48–51) to 0111 (7).
|
||||
uuid_bytes = set_bit(uuid_bytes, 48, 0);
|
||||
uuid_bytes = set_bit(uuid_bytes, 49, 1);
|
||||
uuid_bytes = set_bit(uuid_bytes, 50, 1);
|
||||
uuid_bytes = set_bit(uuid_bytes, 51, 1);
|
||||
|
||||
-- Variant bits (64–65) stay at 10 as inherited from gen_random_uuid().
|
||||
|
||||
RETURN encode(uuid_bytes, 'hex')::uuid;
|
||||
END
|
||||
$$ LANGUAGE plpgsql VOLATILE;
|
||||
|
||||
CREATE TYPE user_plan AS ENUM ('free', 'paid');
|
||||
CREATE TYPE user_gender AS ENUM ('male', 'female');
|
||||
@@ -7,7 +37,7 @@ CREATE TYPE user_goal AS ENUM ('lose', 'maintain', 'gain');
|
||||
CREATE TYPE activity_level AS ENUM ('low', 'moderate', 'high');
|
||||
|
||||
CREATE TABLE users (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
|
||||
firebase_uid VARCHAR(128) NOT NULL UNIQUE,
|
||||
email VARCHAR(255) NOT NULL,
|
||||
name VARCHAR(255) NOT NULL DEFAULT '',
|
||||
@@ -47,3 +77,4 @@ DROP TYPE IF EXISTS activity_level;
|
||||
DROP TYPE IF EXISTS user_goal;
|
||||
DROP TYPE IF EXISTS user_gender;
|
||||
DROP TYPE IF EXISTS user_plan;
|
||||
DROP FUNCTION IF EXISTS uuid_generate_v7();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE ingredient_mappings (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
|
||||
canonical_name VARCHAR(255) NOT NULL,
|
||||
canonical_name_ru VARCHAR(255),
|
||||
spoonacular_id INTEGER UNIQUE,
|
||||
|
||||
@@ -3,7 +3,7 @@ CREATE TYPE recipe_source AS ENUM ('spoonacular', 'ai', 'user');
|
||||
CREATE TYPE recipe_difficulty AS ENUM ('easy', 'medium', 'hard');
|
||||
|
||||
CREATE TABLE recipes (
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
|
||||
source recipe_source NOT NULL DEFAULT 'spoonacular',
|
||||
spoonacular_id INTEGER UNIQUE,
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE saved_recipes (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE products (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
mapping_id UUID REFERENCES ingredient_mappings(id),
|
||||
name TEXT NOT NULL,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
-- +goose Up
|
||||
|
||||
CREATE TABLE menu_plans (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
week_start DATE NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
@@ -9,7 +9,7 @@ CREATE TABLE menu_plans (
|
||||
);
|
||||
|
||||
CREATE TABLE menu_items (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
|
||||
menu_plan_id UUID NOT NULL REFERENCES menu_plans(id) ON DELETE CASCADE,
|
||||
day_of_week INT NOT NULL CHECK (day_of_week BETWEEN 1 AND 7),
|
||||
meal_type TEXT NOT NULL CHECK (meal_type IN ('breakfast','lunch','dinner')),
|
||||
@@ -21,7 +21,7 @@ CREATE TABLE menu_items (
|
||||
-- Stores the generated shopping list for a menu plan.
|
||||
-- items is a JSONB array of {name, category, amount, unit, checked, in_stock}.
|
||||
CREATE TABLE shopping_lists (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
menu_plan_id UUID REFERENCES menu_plans(id) ON DELETE CASCADE,
|
||||
items JSONB NOT NULL DEFAULT '[]',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
-- +goose Up
|
||||
|
||||
CREATE TABLE meal_diary (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
id UUID PRIMARY KEY DEFAULT uuid_generate_v7(),
|
||||
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
date DATE NOT NULL,
|
||||
meal_type TEXT NOT NULL,
|
||||
|
||||
Reference in New Issue
Block a user