mall数据库文件

This commit is contained in:
comlibmb
2026-01-30 16:17:13 +08:00
parent cfec4a16c0
commit 8f181b2b6a
42 changed files with 12758 additions and 2 deletions

View File

@@ -0,0 +1,145 @@
-- ============================================
-- 用户登录 / 注册 - 核心用户资料表结构(创建版 / Create-only
-- ============================================
-- 用途创建核心业务用户资料表ak_users及其相关函数和 RLS 策略。
-- 特点:
-- 1. 不做 DROP/DELETE/TRUNCATE不清空数据
-- 2. 通过 IF NOT EXISTS + 系统表判断,实现可重复执行
-- 3. 职责单一:只负责 ak_users不涉及其他基础表
-- 4. 依赖应在基础表01_create_tables.sql之后执行
-- ============================================
-- ============================================
-- 1. 业务用户资料表 ak_users
-- ============================================
CREATE TABLE IF NOT EXISTS public.ak_users (
id uuid primary key,
username text,
email text,
gender text,
birthday date,
height_cm numeric,
weight_kg numeric,
bio text,
avatar_url text,
preferred_language text,
role text,
school_id text,
grade_id text,
class_id text,
created_at timestamptz default now(),
updated_at timestamptz default now()
);
-- 中文注释
COMMENT ON TABLE public.ak_users IS '业务用户资料表(与 auth.users 一一对应)';
COMMENT ON COLUMN public.ak_users.id IS '用户ID等于 auth.users.id';
COMMENT ON COLUMN public.ak_users.username IS '用户名/昵称';
COMMENT ON COLUMN public.ak_users.email IS '邮箱';
COMMENT ON COLUMN public.ak_users.gender IS '性别';
COMMENT ON COLUMN public.ak_users.birthday IS '生日';
COMMENT ON COLUMN public.ak_users.height_cm IS '身高(厘米)';
COMMENT ON COLUMN public.ak_users.weight_kg IS '体重(公斤)';
COMMENT ON COLUMN public.ak_users.bio IS '个人简介';
COMMENT ON COLUMN public.ak_users.avatar_url IS '头像地址';
COMMENT ON COLUMN public.ak_users.preferred_language IS '偏好语言';
COMMENT ON COLUMN public.ak_users.role IS '角色(如 customer/merchant/admin 等)';
COMMENT ON COLUMN public.ak_users.school_id IS '学校ID可选';
COMMENT ON COLUMN public.ak_users.grade_id IS '年级ID可选';
COMMENT ON COLUMN public.ak_users.class_id IS '班级ID可选';
COMMENT ON COLUMN public.ak_users.created_at IS '创建时间';
COMMENT ON COLUMN public.ak_users.updated_at IS '更新时间';
-- 为 ak_users 添加 updated_at 触发器
-- 注意:通用函数 update_updated_at_column() 在 01_create_tables.sql 中创建
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'update_ak_users_updated_at') THEN
EXECUTE 'CREATE TRIGGER update_ak_users_updated_at BEFORE UPDATE ON public.ak_users FOR EACH ROW EXECUTE FUNCTION public.update_updated_at_column()';
END IF;
END $$;
-- ============================================
-- 2. 行级安全策略RLS
-- ============================================
-- 启用 RLS
ALTER TABLE public.ak_users ENABLE ROW LEVEL SECURITY;
-- 仅允许本人读写自己的资料
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename='ak_users' AND policyname='ak_users_self_select') THEN
EXECUTE 'CREATE POLICY "ak_users_self_select" ON public.ak_users FOR SELECT USING (auth.uid() = id)';
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename='ak_users' AND policyname='ak_users_self_insert') THEN
EXECUTE 'CREATE POLICY "ak_users_self_insert" ON public.ak_users FOR INSERT WITH CHECK (auth.uid() = id)';
END IF;
IF NOT EXISTS (SELECT 1 FROM pg_policies WHERE schemaname='public' AND tablename='ak_users' AND policyname='ak_users_self_update') THEN
EXECUTE 'CREATE POLICY "ak_users_self_update" ON public.ak_users FOR UPDATE USING (auth.uid() = id)';
END IF;
END $$;
-- ============================================
-- 3. 相关函数
-- ============================================
-- 函数1手动初始化/更新用户资料(可选,供前端调用)
CREATE OR REPLACE FUNCTION public.upsert_user_profile(
p_user_id uuid,
p_email text,
p_username text default null
)
RETURNS public.ak_users
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
DECLARE
v_username text := coalesce(p_username, split_part(p_email, '@', 1), 'user');
v_result public.ak_users;
BEGIN
-- 插入或更新用户资料
INSERT INTO public.ak_users (id, email, username)
VALUES (p_user_id, p_email, v_username)
ON CONFLICT (id) DO UPDATE
SET
email = excluded.email,
username = coalesce(excluded.username, ak_users.username)
RETURNING * INTO v_result;
RETURN v_result;
END;
$$;
-- 函数2供 auth.users 触发器使用,自动创建用户资料
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $$
BEGIN
BEGIN
INSERT INTO public.ak_users (id, email, username)
VALUES (NEW.id, NEW.email, COALESCE(SPLIT_PART(NEW.email, '@', 1), 'user'))
ON CONFLICT (id) DO NOTHING;
EXCEPTION WHEN OTHERS THEN
-- 重要:不要因为业务表写入失败而阻断 auth.users 的注册事务
RAISE WARNING 'handle_new_user failed: %', SQLERRM;
END;
RETURN NEW;
END;
$$;
-- ============================================
-- 4. 函数授权
-- ============================================
-- upsert_user_profile 只允许已登录用户调用
REVOKE ALL ON FUNCTION public.upsert_user_profile(uuid, text, text) FROM PUBLIC;
GRANT EXECUTE ON FUNCTION public.upsert_user_profile(uuid, text, text) TO authenticated;
-- handle_new_user 是触发器函数,由系统内部调用,无需对任何角色授权

View File

@@ -0,0 +1,35 @@
-- ============================================
-- 用户登录 / 注册 测试数据
-- 位置pages/user/test/USER_AUTH_TEST_DATA.sql
-- 用途:
-- - 准备少量业务侧测试数据,方便前端联调登录/个人中心
-- - 注意Supabase 的 auth.users 建议通过实际“注册”流程生成,这里不直接插入
-- ============================================
-- 1. 如果你已经通过注册页创建了账号auth.users 中有记录),
-- 可以在 ak_users 中补充一条测试资料:
-- 把 '00000000-0000-0000-0000-000000000001' 替换成自己 auth.users 里的 id。
insert into public.ak_users (id, username, email, role)
values
('00000000-0000-0000-0000-000000000001', 'demo_user', 'demo@example.com', 'analyst')
on conflict (id) do update
set
username = excluded.username,
email = excluded.email,
role = excluded.role;
-- 2. 可选:补充 users / user_sessions 基础数据,方便分析模块统计演示
insert into public.users (id, email, nickname)
values
('00000000-0000-0000-0000-000000000001', 'demo@example.com', 'Demo 分析师')
on conflict (id) do update
set
email = excluded.email,
nickname = excluded.nickname;
insert into public.user_sessions (user_id, session_token, is_active)
values
('00000000-0000-0000-0000-000000000001', 'demo-session-token', true);

View File

@@ -0,0 +1,89 @@
-- ============================================
-- 自动创建 ak_users 记录的触发器
-- ============================================
-- 位置pages/user/test/USER_AUTH_TRIGGER.sql
-- 用途:当 auth.users 表中创建新用户时,自动在 ak_users 表中创建对应的业务资料记录
--
-- 执行方式:
-- 在 Supabase Dashboard 的 SQL Editor 中执行此文件
-- 需要 superuser 权限Dashboard 默认有)
-- ============================================
-- 触发器函数 `public.handle_new_user()` 的定义在 `USER_AUTH_SCHEMA.sql` 中完成。
-- 这里仅负责在 auth.users 上创建触发器(避免重复定义函数导致版本不一致)。
-- 兼容处理:如果 `public.handle_new_user()` 尚未创建(例如先执行了本文件),则在此处补齐创建。
-- 说明:这里采用“存在则跳过”的创建方式,不会覆盖已有实现。
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1
FROM pg_proc p
JOIN pg_namespace n ON n.oid = p.pronamespace
WHERE n.nspname = 'public'
AND p.proname = 'handle_new_user'
) THEN
EXECUTE $fn$
CREATE FUNCTION public.handle_new_user()
RETURNS TRIGGER
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = public
AS $body$
BEGIN
BEGIN
INSERT INTO public.ak_users (id, email, username)
VALUES (
NEW.id,
NEW.email,
COALESCE(SPLIT_PART(NEW.email, '@', 1), 'user')
)
ON CONFLICT (id) DO NOTHING;
EXCEPTION WHEN OTHERS THEN
RAISE WARNING 'handle_new_user failed: %', SQLERRM;
END;
RETURN NEW;
END;
$body$;
$fn$;
END IF;
END $$;
-- 在 auth.users 表上创建触发器
-- 注意:这个触发器会在每次 auth.users 插入新记录时自动执行
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_trigger WHERE tgname = 'on_auth_user_created') THEN
EXECUTE 'CREATE TRIGGER on_auth_user_created AFTER INSERT ON auth.users FOR EACH ROW EXECUTE FUNCTION public.handle_new_user()';
END IF;
END $$;
-- ============================================
-- 验证触发器
-- ============================================
-- 执行以下查询验证触发器是否创建成功:
-- SELECT * FROM pg_trigger WHERE tgname = 'on_auth_user_created';
-- SELECT * FROM pg_proc WHERE proname = 'handle_new_user';
-- ============================================
-- 测试触发器(可选)
-- ============================================
-- 注意:以下测试代码会创建一个测试用户,执行前请确认
--
-- 1. 通过 Supabase Auth API 注册一个新用户
-- 2. 检查 ak_users 表中是否自动创建了对应的记录
--
-- 或者手动测试(需要 admin 权限):
-- INSERT INTO auth.users (id, email, encrypted_password, email_confirmed_at, created_at, updated_at)
-- VALUES (
-- gen_random_uuid(),
-- 'test@example.com',
-- crypt('password', gen_salt('bf')),
-- NOW(),
-- NOW(),
-- NOW()
-- );
--
-- 然后检查 ak_users 表:
-- SELECT * FROM ak_users WHERE email = 'test@example.com';