Skip to content
Loafacto 문서/참고 문서/web-ui 문서/02. supabase-profiles.sql

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;