-- ============================================================================= -- app schema DDL — 面向外部访问的视图/函数 + RLS 策略 -- 说明:以视图封装 DWS/Core 层数据,所有视图启用 RLS,以 site_id 过滤 -- 不存储实际数据,仅做访问层 -- ============================================================================= CREATE SCHEMA IF NOT EXISTS app; SET search_path TO app; -- ----------------------------------------------------------------------------- -- 应用角色(供 FDW 和外部应用使用) -- ----------------------------------------------------------------------------- DO $$ BEGIN IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'app_reader') THEN CREATE ROLE app_reader; END IF; END $$; GRANT USAGE ON SCHEMA app TO app_reader; GRANT USAGE ON SCHEMA core TO app_reader; GRANT USAGE ON SCHEMA dws TO app_reader; -- ============================================================================= -- 第一部分:基于 Core 层的视图 -- ============================================================================= -- ----------------------------------------------------------------------------- -- 1. v_site — 门店视图 -- ----------------------------------------------------------------------------- CREATE OR REPLACE VIEW app.v_site AS SELECT s.site_id, s.tenant_id, s.shop_name, s.site_label, s.shop_status FROM core.dim_site s; COMMENT ON VIEW app.v_site IS '门店视图:封装 core.dim_site,供外部应用访问。'; -- ----------------------------------------------------------------------------- -- 2. v_member — 会员视图 -- ----------------------------------------------------------------------------- CREATE OR REPLACE VIEW app.v_member AS SELECT m.member_id, m.system_member_id, m.tenant_id, m.register_site_id AS site_id, m.mobile, m.nickname, m.member_card_grade_name, m.status FROM core.dim_member m; COMMENT ON VIEW app.v_member IS '会员视图:封装 core.dim_member,以 register_site_id 作为 site_id。'; -- ----------------------------------------------------------------------------- -- 3. v_assistant — 助教视图 -- ----------------------------------------------------------------------------- CREATE OR REPLACE VIEW app.v_assistant AS SELECT a.assistant_id, a.tenant_id, a.site_id, a.real_name, a.nickname, a.mobile, a.level, a.assistant_status, a.leave_status FROM core.dim_assistant a; COMMENT ON VIEW app.v_assistant IS '助教视图:封装 core.dim_assistant。'; -- ============================================================================= -- 第二部分:基于 DWS 层的汇总视图 -- ============================================================================= -- ----------------------------------------------------------------------------- -- 4. v_assistant_daily — 助教日明细视图 -- ----------------------------------------------------------------------------- CREATE OR REPLACE VIEW app.v_assistant_daily AS SELECT d.id, d.site_id, d.assistant_id, d.stat_date, d.total_service_hours, d.total_service_count, d.total_revenue, d.basic_hours, d.extra_hours, d.tip_hours, d.created_at FROM dws.dws_assistant_daily_detail d; COMMENT ON VIEW app.v_assistant_daily IS '助教日明细视图:封装 dws.dws_assistant_daily_detail。'; -- ----------------------------------------------------------------------------- -- 5. v_finance_daily — 财务日报视图 -- ----------------------------------------------------------------------------- CREATE OR REPLACE VIEW app.v_finance_daily AS SELECT f.id, f.site_id, f.stat_date, f.total_revenue, f.table_fee_revenue, f.goods_revenue, f.assistant_revenue, f.recharge_revenue, f.total_orders, f.total_customers, f.created_at FROM dws.dws_finance_daily_summary f; COMMENT ON VIEW app.v_finance_daily IS '财务日报视图:封装 dws.dws_finance_daily_summary。'; -- ----------------------------------------------------------------------------- -- 6. v_member_consumption — 会员消费汇总视图 -- ----------------------------------------------------------------------------- CREATE OR REPLACE VIEW app.v_member_consumption AS SELECT mc.id, mc.site_id, mc.member_id, mc.total_visits, mc.total_consumption, mc.last_visit_date, mc.first_visit_date, mc.avg_consumption, mc.created_at FROM dws.dws_member_consumption_summary mc; COMMENT ON VIEW app.v_member_consumption IS '会员消费汇总视图:封装 dws.dws_member_consumption_summary。'; -- ----------------------------------------------------------------------------- -- 7. v_order_summary — 订单汇总视图 -- ----------------------------------------------------------------------------- CREATE OR REPLACE VIEW app.v_order_summary AS SELECT os.site_id, os.order_settle_id, os.order_trade_no, os.member_id, os.total_amount, os.actual_amount, os.settle_time, os.pay_status, os.created_at FROM dws.dws_order_summary os; COMMENT ON VIEW app.v_order_summary IS '订单汇总视图:封装 dws.dws_order_summary。'; -- ============================================================================= -- 第三部分:RLS 策略 -- 说明:所有视图基于 site_id 隔离,通过会话变量 app.current_site_id 过滤 -- 使用方式:SET app.current_site_id = '2790685415443269'; -- ============================================================================= -- 对视图底层表启用 RLS(视图本身不支持 RLS,需在底层表上设置) -- 由于 app schema 的视图引用 core/dws 表,RLS 需在源表上配置 -- core 层 RLS ALTER TABLE core.dim_site ENABLE ROW LEVEL SECURITY; ALTER TABLE core.dim_member ENABLE ROW LEVEL SECURITY; ALTER TABLE core.dim_assistant ENABLE ROW LEVEL SECURITY; ALTER TABLE core.dim_table ENABLE ROW LEVEL SECURITY; ALTER TABLE core.fact_settlement ENABLE ROW LEVEL SECURITY; ALTER TABLE core.fact_payment ENABLE ROW LEVEL SECURITY; -- core 层策略 CREATE POLICY site_isolation_dim_site ON core.dim_site FOR SELECT TO app_reader USING (site_id = current_setting('app.current_site_id')::bigint); CREATE POLICY site_isolation_dim_member ON core.dim_member FOR SELECT TO app_reader USING (register_site_id = current_setting('app.current_site_id')::bigint); CREATE POLICY site_isolation_dim_assistant ON core.dim_assistant FOR SELECT TO app_reader USING (site_id = current_setting('app.current_site_id')::bigint); CREATE POLICY site_isolation_dim_table ON core.dim_table FOR SELECT TO app_reader USING (site_id = current_setting('app.current_site_id')::bigint); CREATE POLICY site_isolation_fact_settlement ON core.fact_settlement FOR SELECT TO app_reader USING (site_id = current_setting('app.current_site_id')::bigint); CREATE POLICY site_isolation_fact_payment ON core.fact_payment FOR SELECT TO app_reader USING (site_id = current_setting('app.current_site_id')::bigint); -- ============================================================================= -- 第四部分:授权 -- ============================================================================= -- 授予 app_reader 对 core 表的 SELECT 权限 GRANT SELECT ON ALL TABLES IN SCHEMA core TO app_reader; GRANT SELECT ON ALL TABLES IN SCHEMA app TO app_reader; -- 授予对 dws 表的 SELECT 权限(视图需要) GRANT SELECT ON ALL TABLES IN SCHEMA dws TO app_reader; -- 设置默认权限(未来新建的表自动授权) ALTER DEFAULT PRIVILEGES IN SCHEMA core GRANT SELECT ON TABLES TO app_reader; ALTER DEFAULT PRIVILEGES IN SCHEMA app GRANT SELECT ON TABLES TO app_reader; ALTER DEFAULT PRIVILEGES IN SCHEMA dws GRANT SELECT ON TABLES TO app_reader;