Appearance
02. supabase-profiles.sql
원본 파일: 'C:\Repository\loafacto-hub\docs\web-ui\02. supabase-profiles.sql'
sql
-- =============================================================================
-- 프로필(닉네임) 테이블 및 중복 검사 / 저장 RPC
-- Supabase SQL Editor에서 user_roles 적용 후 이 파일을 실행하세요.
-- =============================================================================
-- 1) 프로필 테이블 (닉네임 = display_name, 중복 불가)
CREATE TABLE IF NOT EXISTS public.profiles (
user_id uuid PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
display_name text NOT NULL,
created_at timestamptz DEFAULT now() NOT NULL,
updated_at timestamptz DEFAULT now() NOT NULL
);
COMMENT ON TABLE public.profiles IS '사용자 프로필(닉네임). 닉네임 중복 불가.';
-- 2) 닉네임 유일 (대소문자·앞뒤 공백 무시)
CREATE UNIQUE INDEX IF NOT EXISTS profiles_display_name_lower_key
ON public.profiles (LOWER(TRIM(display_name)));
-- 3) RLS
ALTER TABLE public.profiles ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users can read all profiles for nickname check"
ON public.profiles
FOR SELECT
TO authenticated
USING (true);
CREATE POLICY "Users can insert own profile"
ON public.profiles
FOR INSERT
TO authenticated
WITH CHECK (auth.uid() = user_id);
CREATE POLICY "Users can update own profile"
ON public.profiles
FOR UPDATE
TO authenticated
USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);
-- 4) RPC: 닉네임 사용 가능 여부 (다른 유저가 같은 닉네임 쓰는지)
CREATE OR REPLACE FUNCTION public.check_display_name_available(display_name text)
RETURNS boolean
LANGUAGE sql
STABLE
SECURITY DEFINER
SET search_path = public
AS $$
SELECT NOT EXISTS (
SELECT 1 FROM public.profiles p
WHERE LOWER(TRIM(p.display_name)) = LOWER(TRIM(display_name))
AND p.user_id != auth.uid()
);
$$;
COMMENT ON FUNCTION public.check_display_name_available(text) IS '다른 유저가 해당 닉네임을 쓰지 않으면 true.';
GRANT EXECUTE ON FUNCTION public.check_display_name_available(text) TO authenticated;
-- 5) RPC: 내 프로필 닉네임 저장 (profiles 테이블에 반영)
CREATE OR REPLACE FUNCTION public.set_my_display_name(display_name text)
RETURNS void
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
n text := TRIM(display_name);
BEGIN
IF n = '' OR LENGTH(n) < 2 THEN
RAISE EXCEPTION 'display_name must be at least 2 characters';
END IF;
INSERT INTO public.profiles (user_id, display_name)
VALUES (auth.uid(), n)
ON CONFLICT (user_id) DO UPDATE SET
display_name = EXCLUDED.display_name,
updated_at = now();
END;
$$;
COMMENT ON FUNCTION public.set_my_display_name(text) IS '현재 사용자의 닉네임 저장. unique 위반 시 에러.';
GRANT EXECUTE ON FUNCTION public.set_my_display_name(text) TO authenticated;