[SAAS-021] feat: Add MLM module DDL
- 6 tables: structures, ranks, nodes, commissions, bonuses, rank_history - 5 enums: structure_type, node_status, commission_type, commission_status, bonus_type - LTREE extension for hierarchical path queries - 24 RLS policies for multi-tenancy - GIST index for LTREE path column Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
6e5244b612
commit
2837480e17
20
ddl/schemas/mlm/00-schema.sql
Normal file
20
ddl/schemas/mlm/00-schema.sql
Normal file
@ -0,0 +1,20 @@
|
||||
-- =============================================
|
||||
-- Schema: mlm
|
||||
-- Module: SAAS-021 MLM (Multi-Level Marketing)
|
||||
-- =============================================
|
||||
|
||||
-- Crear schema
|
||||
CREATE SCHEMA IF NOT EXISTS mlm;
|
||||
|
||||
-- Comentario
|
||||
COMMENT ON SCHEMA mlm IS 'MLM multi-level marketing module - network structures, nodes, ranks, and commissions';
|
||||
|
||||
-- Grants
|
||||
GRANT USAGE ON SCHEMA mlm TO template_saas_user;
|
||||
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA mlm TO template_saas_user;
|
||||
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA mlm TO template_saas_user;
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA mlm GRANT ALL PRIVILEGES ON TABLES TO template_saas_user;
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA mlm GRANT ALL PRIVILEGES ON SEQUENCES TO template_saas_user;
|
||||
|
||||
-- Enable LTREE extension (required for hierarchical path queries)
|
||||
CREATE EXTENSION IF NOT EXISTS ltree;
|
||||
55
ddl/schemas/mlm/01-enums.sql
Normal file
55
ddl/schemas/mlm/01-enums.sql
Normal file
@ -0,0 +1,55 @@
|
||||
-- =============================================
|
||||
-- Enums: mlm
|
||||
-- Module: SAAS-021 MLM (Multi-Level Marketing)
|
||||
-- =============================================
|
||||
|
||||
-- Structure type
|
||||
CREATE TYPE mlm.structure_type AS ENUM (
|
||||
'unilevel', -- Unlimited width, limited depth
|
||||
'binary', -- Max 2 children per node
|
||||
'matrix', -- Fixed width x depth
|
||||
'hybrid' -- Custom configuration
|
||||
);
|
||||
|
||||
COMMENT ON TYPE mlm.structure_type IS 'Types of MLM network structures';
|
||||
|
||||
-- Node status
|
||||
CREATE TYPE mlm.node_status AS ENUM (
|
||||
'pending', -- Awaiting activation
|
||||
'active', -- Active in network
|
||||
'inactive', -- Temporarily inactive
|
||||
'suspended' -- Administratively suspended
|
||||
);
|
||||
|
||||
COMMENT ON TYPE mlm.node_status IS 'Status of a node in the network';
|
||||
|
||||
-- Commission type
|
||||
CREATE TYPE mlm.commission_type AS ENUM (
|
||||
'level', -- Direct level commission (1st gen, 2nd gen, etc.)
|
||||
'matching', -- Matching bonus from downline earnings
|
||||
'infinity', -- Infinity bonus (unlimited depth after rank)
|
||||
'leadership', -- Leadership bonus for qualified ranks
|
||||
'pool' -- Pool share bonus
|
||||
);
|
||||
|
||||
COMMENT ON TYPE mlm.commission_type IS 'Types of MLM commissions';
|
||||
|
||||
-- Commission status
|
||||
CREATE TYPE mlm.commission_status AS ENUM (
|
||||
'pending', -- Awaiting approval
|
||||
'approved', -- Approved for payment
|
||||
'paid', -- Paid out
|
||||
'cancelled' -- Cancelled
|
||||
);
|
||||
|
||||
COMMENT ON TYPE mlm.commission_status IS 'Status of a commission entry';
|
||||
|
||||
-- Bonus type
|
||||
CREATE TYPE mlm.bonus_type AS ENUM (
|
||||
'rank_achievement', -- One-time bonus for reaching rank
|
||||
'rank_maintenance', -- Monthly bonus for maintaining rank
|
||||
'fast_start', -- Fast start bonus for quick enrollments
|
||||
'pool_share' -- Share of global pool
|
||||
);
|
||||
|
||||
COMMENT ON TYPE mlm.bonus_type IS 'Types of bonuses in MLM';
|
||||
235
ddl/schemas/mlm/02-tables.sql
Normal file
235
ddl/schemas/mlm/02-tables.sql
Normal file
@ -0,0 +1,235 @@
|
||||
-- =============================================
|
||||
-- Tables: mlm
|
||||
-- Module: SAAS-021 MLM (Multi-Level Marketing)
|
||||
-- =============================================
|
||||
|
||||
-- ─────────────────────────────────────────────
|
||||
-- structures - MLM network structure configuration
|
||||
-- ─────────────────────────────────────────────
|
||||
CREATE TABLE mlm.structures (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,
|
||||
|
||||
name VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
type mlm.structure_type NOT NULL,
|
||||
|
||||
-- Configuration per type (JSONB)
|
||||
-- Unilevel: { max_width: null, max_depth: 10 }
|
||||
-- Binary: { spillover: 'left_first' | 'weak_leg' | 'balanced' }
|
||||
-- Matrix: { width: 3, depth: 7 }
|
||||
config JSONB NOT NULL DEFAULT '{}',
|
||||
|
||||
-- Commission rates by level (JSONB array)
|
||||
-- [{ level: 1, rate: 0.10 }, { level: 2, rate: 0.05 }, ...]
|
||||
level_rates JSONB NOT NULL DEFAULT '[]',
|
||||
|
||||
-- Matching bonus rates (for matching commissions)
|
||||
matching_rates JSONB DEFAULT '[]',
|
||||
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
created_by UUID REFERENCES users.users(id) ON DELETE SET NULL,
|
||||
|
||||
CONSTRAINT unique_structure_name_per_tenant UNIQUE (tenant_id, name)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE mlm.structures IS 'MLM network structure configurations';
|
||||
COMMENT ON COLUMN mlm.structures.config IS 'Structure-specific configuration (max_depth, spillover, etc.)';
|
||||
COMMENT ON COLUMN mlm.structures.level_rates IS 'Commission percentages by level depth';
|
||||
|
||||
-- Trigger for updated_at
|
||||
CREATE TRIGGER set_structures_updated_at
|
||||
BEFORE UPDATE ON mlm.structures
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.set_updated_at();
|
||||
|
||||
-- ─────────────────────────────────────────────
|
||||
-- ranks - MLM qualification ranks
|
||||
-- ─────────────────────────────────────────────
|
||||
CREATE TABLE mlm.ranks (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,
|
||||
structure_id UUID NOT NULL REFERENCES mlm.structures(id) ON DELETE CASCADE,
|
||||
|
||||
name VARCHAR(100) NOT NULL,
|
||||
level INTEGER NOT NULL, -- 1=Entry, 2=Bronze, 3=Silver, etc.
|
||||
badge_url VARCHAR(500),
|
||||
color VARCHAR(7), -- Hex color for UI
|
||||
|
||||
-- Requirements to achieve rank (JSONB)
|
||||
-- {
|
||||
-- personal_volume: 1000,
|
||||
-- group_volume: 10000,
|
||||
-- direct_referrals: 3,
|
||||
-- active_legs: 2,
|
||||
-- rank_in_legs: { rank_level: 2, count: 1 }
|
||||
-- }
|
||||
requirements JSONB NOT NULL DEFAULT '{}',
|
||||
|
||||
-- Benefits for this rank
|
||||
bonus_rate DECIMAL(10,4), -- Additional bonus percentage
|
||||
benefits JSONB DEFAULT '{}', -- Other benefits (discounts, access, etc.)
|
||||
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
|
||||
CONSTRAINT unique_rank_level_per_structure UNIQUE (structure_id, level)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE mlm.ranks IS 'MLM qualification ranks with requirements and benefits';
|
||||
COMMENT ON COLUMN mlm.ranks.requirements IS 'Conditions to achieve this rank';
|
||||
|
||||
-- Trigger for updated_at
|
||||
CREATE TRIGGER set_ranks_updated_at
|
||||
BEFORE UPDATE ON mlm.ranks
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.set_updated_at();
|
||||
|
||||
-- ─────────────────────────────────────────────
|
||||
-- nodes - MLM network nodes (distributors)
|
||||
-- ─────────────────────────────────────────────
|
||||
CREATE TABLE mlm.nodes (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,
|
||||
structure_id UUID NOT NULL REFERENCES mlm.structures(id) ON DELETE CASCADE,
|
||||
|
||||
user_id UUID NOT NULL REFERENCES users.users(id) ON DELETE CASCADE,
|
||||
|
||||
-- Hierarchy
|
||||
parent_id UUID REFERENCES mlm.nodes(id) ON DELETE SET NULL,
|
||||
sponsor_id UUID REFERENCES mlm.nodes(id) ON DELETE SET NULL, -- Who referred them
|
||||
position INTEGER, -- For binary: 1=left, 2=right. For matrix: 1,2,3...width
|
||||
|
||||
-- Materialized path for efficient queries (LTREE)
|
||||
path LTREE,
|
||||
depth INTEGER DEFAULT 0,
|
||||
|
||||
-- Current and highest rank
|
||||
rank_id UUID REFERENCES mlm.ranks(id) ON DELETE SET NULL,
|
||||
highest_rank_id UUID REFERENCES mlm.ranks(id) ON DELETE SET NULL,
|
||||
|
||||
-- Performance metrics
|
||||
personal_volume DECIMAL(15,2) DEFAULT 0,
|
||||
group_volume DECIMAL(15,2) DEFAULT 0,
|
||||
direct_referrals INTEGER DEFAULT 0,
|
||||
total_downline INTEGER DEFAULT 0,
|
||||
|
||||
-- Lifetime earnings
|
||||
total_earnings DECIMAL(15,2) DEFAULT 0,
|
||||
|
||||
-- Status
|
||||
status mlm.node_status NOT NULL DEFAULT 'active',
|
||||
joined_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
|
||||
-- Invitation
|
||||
invite_code VARCHAR(20) UNIQUE,
|
||||
|
||||
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
|
||||
CONSTRAINT unique_user_per_structure UNIQUE (structure_id, user_id)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE mlm.nodes IS 'MLM network nodes representing distributors in the hierarchy';
|
||||
COMMENT ON COLUMN mlm.nodes.path IS 'LTREE path for efficient ancestor/descendant queries';
|
||||
COMMENT ON COLUMN mlm.nodes.position IS 'Position under parent (left/right for binary, slot for matrix)';
|
||||
|
||||
-- Trigger for updated_at
|
||||
CREATE TRIGGER set_nodes_updated_at
|
||||
BEFORE UPDATE ON mlm.nodes
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION public.set_updated_at();
|
||||
|
||||
-- ─────────────────────────────────────────────
|
||||
-- commissions - MLM commission entries
|
||||
-- ─────────────────────────────────────────────
|
||||
CREATE TABLE mlm.commissions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,
|
||||
|
||||
node_id UUID NOT NULL REFERENCES mlm.nodes(id) ON DELETE CASCADE, -- Who receives
|
||||
source_node_id UUID NOT NULL REFERENCES mlm.nodes(id) ON DELETE CASCADE, -- Who generated
|
||||
|
||||
-- Commission type
|
||||
type mlm.commission_type NOT NULL,
|
||||
|
||||
-- Level difference (1 = direct, 2 = second level, etc.)
|
||||
level INTEGER NOT NULL,
|
||||
|
||||
-- Amounts
|
||||
source_amount DECIMAL(15,2) NOT NULL, -- Original sale/volume amount
|
||||
rate_applied DECIMAL(10,4) NOT NULL, -- Rate used for calculation
|
||||
commission_amount DECIMAL(15,2) NOT NULL, -- Final commission
|
||||
currency VARCHAR(3) DEFAULT 'USD',
|
||||
|
||||
-- Reference to period and source
|
||||
period_id UUID REFERENCES commissions.periods(id) ON DELETE SET NULL,
|
||||
source_reference VARCHAR(200), -- Reference to sale/transaction
|
||||
|
||||
-- Status
|
||||
status mlm.commission_status NOT NULL DEFAULT 'pending',
|
||||
paid_at TIMESTAMPTZ,
|
||||
|
||||
notes TEXT,
|
||||
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE mlm.commissions IS 'MLM commission entries from downline activity';
|
||||
COMMENT ON COLUMN mlm.commissions.level IS 'Level depth from source to beneficiary';
|
||||
|
||||
-- ─────────────────────────────────────────────
|
||||
-- bonuses - MLM bonus entries
|
||||
-- ─────────────────────────────────────────────
|
||||
CREATE TABLE mlm.bonuses (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,
|
||||
|
||||
node_id UUID NOT NULL REFERENCES mlm.nodes(id) ON DELETE CASCADE,
|
||||
rank_id UUID REFERENCES mlm.ranks(id) ON DELETE SET NULL,
|
||||
|
||||
type mlm.bonus_type NOT NULL,
|
||||
amount DECIMAL(15,2) NOT NULL,
|
||||
currency VARCHAR(3) DEFAULT 'USD',
|
||||
|
||||
-- Reference to period
|
||||
period_id UUID REFERENCES commissions.periods(id) ON DELETE SET NULL,
|
||||
|
||||
-- Status
|
||||
status mlm.commission_status NOT NULL DEFAULT 'pending',
|
||||
paid_at TIMESTAMPTZ,
|
||||
|
||||
achieved_at TIMESTAMPTZ DEFAULT NOW(),
|
||||
notes TEXT,
|
||||
|
||||
created_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE mlm.bonuses IS 'MLM bonus entries for rank achievements and other bonuses';
|
||||
|
||||
-- ─────────────────────────────────────────────
|
||||
-- rank_history - Historical rank achievements
|
||||
-- ─────────────────────────────────────────────
|
||||
CREATE TABLE mlm.rank_history (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,
|
||||
|
||||
node_id UUID NOT NULL REFERENCES mlm.nodes(id) ON DELETE CASCADE,
|
||||
rank_id UUID NOT NULL REFERENCES mlm.ranks(id) ON DELETE CASCADE,
|
||||
|
||||
previous_rank_id UUID REFERENCES mlm.ranks(id) ON DELETE SET NULL,
|
||||
|
||||
-- Snapshot of metrics at achievement
|
||||
personal_volume_at DECIMAL(15,2),
|
||||
group_volume_at DECIMAL(15,2),
|
||||
direct_referrals_at INTEGER,
|
||||
|
||||
achieved_at TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
COMMENT ON TABLE mlm.rank_history IS 'Historical record of rank achievements';
|
||||
126
ddl/schemas/mlm/04-rls.sql
Normal file
126
ddl/schemas/mlm/04-rls.sql
Normal file
@ -0,0 +1,126 @@
|
||||
-- =============================================
|
||||
-- RLS Policies: mlm
|
||||
-- Module: SAAS-021 MLM (Multi-Level Marketing)
|
||||
-- =============================================
|
||||
|
||||
-- Enable RLS on all tables
|
||||
ALTER TABLE mlm.structures ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE mlm.ranks ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE mlm.nodes ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE mlm.commissions ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE mlm.bonuses ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE mlm.rank_history ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- ─────────────────────────────────────────────
|
||||
-- structures policies
|
||||
-- ─────────────────────────────────────────────
|
||||
CREATE POLICY structures_tenant_isolation_select
|
||||
ON mlm.structures FOR SELECT
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
CREATE POLICY structures_tenant_isolation_insert
|
||||
ON mlm.structures FOR INSERT
|
||||
WITH CHECK (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
CREATE POLICY structures_tenant_isolation_update
|
||||
ON mlm.structures FOR UPDATE
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
CREATE POLICY structures_tenant_isolation_delete
|
||||
ON mlm.structures FOR DELETE
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
-- ─────────────────────────────────────────────
|
||||
-- ranks policies
|
||||
-- ─────────────────────────────────────────────
|
||||
CREATE POLICY ranks_tenant_isolation_select
|
||||
ON mlm.ranks FOR SELECT
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
CREATE POLICY ranks_tenant_isolation_insert
|
||||
ON mlm.ranks FOR INSERT
|
||||
WITH CHECK (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
CREATE POLICY ranks_tenant_isolation_update
|
||||
ON mlm.ranks FOR UPDATE
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
CREATE POLICY ranks_tenant_isolation_delete
|
||||
ON mlm.ranks FOR DELETE
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
-- ─────────────────────────────────────────────
|
||||
-- nodes policies
|
||||
-- ─────────────────────────────────────────────
|
||||
CREATE POLICY nodes_tenant_isolation_select
|
||||
ON mlm.nodes FOR SELECT
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
CREATE POLICY nodes_tenant_isolation_insert
|
||||
ON mlm.nodes FOR INSERT
|
||||
WITH CHECK (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
CREATE POLICY nodes_tenant_isolation_update
|
||||
ON mlm.nodes FOR UPDATE
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
CREATE POLICY nodes_tenant_isolation_delete
|
||||
ON mlm.nodes FOR DELETE
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
-- ─────────────────────────────────────────────
|
||||
-- commissions policies
|
||||
-- ─────────────────────────────────────────────
|
||||
CREATE POLICY commissions_tenant_isolation_select
|
||||
ON mlm.commissions FOR SELECT
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
CREATE POLICY commissions_tenant_isolation_insert
|
||||
ON mlm.commissions FOR INSERT
|
||||
WITH CHECK (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
CREATE POLICY commissions_tenant_isolation_update
|
||||
ON mlm.commissions FOR UPDATE
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
CREATE POLICY commissions_tenant_isolation_delete
|
||||
ON mlm.commissions FOR DELETE
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
-- ─────────────────────────────────────────────
|
||||
-- bonuses policies
|
||||
-- ─────────────────────────────────────────────
|
||||
CREATE POLICY bonuses_tenant_isolation_select
|
||||
ON mlm.bonuses FOR SELECT
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
CREATE POLICY bonuses_tenant_isolation_insert
|
||||
ON mlm.bonuses FOR INSERT
|
||||
WITH CHECK (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
CREATE POLICY bonuses_tenant_isolation_update
|
||||
ON mlm.bonuses FOR UPDATE
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
CREATE POLICY bonuses_tenant_isolation_delete
|
||||
ON mlm.bonuses FOR DELETE
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
-- ─────────────────────────────────────────────
|
||||
-- rank_history policies
|
||||
-- ─────────────────────────────────────────────
|
||||
CREATE POLICY rank_history_tenant_isolation_select
|
||||
ON mlm.rank_history FOR SELECT
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
CREATE POLICY rank_history_tenant_isolation_insert
|
||||
ON mlm.rank_history FOR INSERT
|
||||
WITH CHECK (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
CREATE POLICY rank_history_tenant_isolation_update
|
||||
ON mlm.rank_history FOR UPDATE
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
|
||||
CREATE POLICY rank_history_tenant_isolation_delete
|
||||
ON mlm.rank_history FOR DELETE
|
||||
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
87
ddl/schemas/mlm/05-indexes.sql
Normal file
87
ddl/schemas/mlm/05-indexes.sql
Normal file
@ -0,0 +1,87 @@
|
||||
-- =============================================
|
||||
-- Indexes: mlm
|
||||
-- Module: SAAS-021 MLM (Multi-Level Marketing)
|
||||
-- =============================================
|
||||
|
||||
-- ─────────────────────────────────────────────
|
||||
-- structures indexes
|
||||
-- ─────────────────────────────────────────────
|
||||
CREATE INDEX idx_structures_tenant ON mlm.structures (tenant_id);
|
||||
CREATE INDEX idx_structures_active ON mlm.structures (tenant_id, is_active) WHERE is_active = true;
|
||||
CREATE INDEX idx_structures_type ON mlm.structures (tenant_id, type);
|
||||
|
||||
-- ─────────────────────────────────────────────
|
||||
-- ranks indexes
|
||||
-- ─────────────────────────────────────────────
|
||||
CREATE INDEX idx_ranks_tenant ON mlm.ranks (tenant_id);
|
||||
CREATE INDEX idx_ranks_structure ON mlm.ranks (structure_id);
|
||||
CREATE INDEX idx_ranks_level ON mlm.ranks (structure_id, level);
|
||||
CREATE INDEX idx_ranks_active ON mlm.ranks (structure_id, is_active) WHERE is_active = true;
|
||||
|
||||
-- ─────────────────────────────────────────────
|
||||
-- nodes indexes (CRITICAL for performance)
|
||||
-- ─────────────────────────────────────────────
|
||||
-- Tenant isolation
|
||||
CREATE INDEX idx_nodes_tenant ON mlm.nodes (tenant_id);
|
||||
|
||||
-- Structure lookup
|
||||
CREATE INDEX idx_nodes_structure ON mlm.nodes (structure_id);
|
||||
|
||||
-- User lookup
|
||||
CREATE INDEX idx_nodes_user ON mlm.nodes (user_id);
|
||||
|
||||
-- Hierarchy lookups
|
||||
CREATE INDEX idx_nodes_parent ON mlm.nodes (parent_id);
|
||||
CREATE INDEX idx_nodes_sponsor ON mlm.nodes (sponsor_id);
|
||||
|
||||
-- LTREE path index (for ancestor/descendant queries)
|
||||
CREATE INDEX idx_nodes_path ON mlm.nodes USING GIST (path);
|
||||
|
||||
-- Depth-based queries
|
||||
CREATE INDEX idx_nodes_depth ON mlm.nodes (structure_id, depth);
|
||||
|
||||
-- Status filtering
|
||||
CREATE INDEX idx_nodes_status ON mlm.nodes (structure_id, status);
|
||||
CREATE INDEX idx_nodes_active ON mlm.nodes (structure_id) WHERE status = 'active';
|
||||
|
||||
-- Rank lookups
|
||||
CREATE INDEX idx_nodes_rank ON mlm.nodes (rank_id);
|
||||
|
||||
-- Invite code lookup
|
||||
CREATE INDEX idx_nodes_invite_code ON mlm.nodes (invite_code) WHERE invite_code IS NOT NULL;
|
||||
|
||||
-- Combined for common queries
|
||||
CREATE INDEX idx_nodes_structure_parent ON mlm.nodes (structure_id, parent_id);
|
||||
CREATE INDEX idx_nodes_structure_user ON mlm.nodes (structure_id, user_id);
|
||||
|
||||
-- ─────────────────────────────────────────────
|
||||
-- commissions indexes
|
||||
-- ─────────────────────────────────────────────
|
||||
CREATE INDEX idx_commissions_tenant ON mlm.commissions (tenant_id);
|
||||
CREATE INDEX idx_commissions_node ON mlm.commissions (node_id);
|
||||
CREATE INDEX idx_commissions_source_node ON mlm.commissions (source_node_id);
|
||||
CREATE INDEX idx_commissions_type ON mlm.commissions (tenant_id, type);
|
||||
CREATE INDEX idx_commissions_level ON mlm.commissions (tenant_id, level);
|
||||
CREATE INDEX idx_commissions_status ON mlm.commissions (tenant_id, status);
|
||||
CREATE INDEX idx_commissions_period ON mlm.commissions (period_id);
|
||||
CREATE INDEX idx_commissions_pending ON mlm.commissions (tenant_id) WHERE status = 'pending';
|
||||
CREATE INDEX idx_commissions_created ON mlm.commissions (tenant_id, created_at DESC);
|
||||
|
||||
-- ─────────────────────────────────────────────
|
||||
-- bonuses indexes
|
||||
-- ─────────────────────────────────────────────
|
||||
CREATE INDEX idx_bonuses_tenant ON mlm.bonuses (tenant_id);
|
||||
CREATE INDEX idx_bonuses_node ON mlm.bonuses (node_id);
|
||||
CREATE INDEX idx_bonuses_rank ON mlm.bonuses (rank_id);
|
||||
CREATE INDEX idx_bonuses_type ON mlm.bonuses (tenant_id, type);
|
||||
CREATE INDEX idx_bonuses_status ON mlm.bonuses (tenant_id, status);
|
||||
CREATE INDEX idx_bonuses_period ON mlm.bonuses (period_id);
|
||||
CREATE INDEX idx_bonuses_pending ON mlm.bonuses (tenant_id) WHERE status = 'pending';
|
||||
|
||||
-- ─────────────────────────────────────────────
|
||||
-- rank_history indexes
|
||||
-- ─────────────────────────────────────────────
|
||||
CREATE INDEX idx_rank_history_tenant ON mlm.rank_history (tenant_id);
|
||||
CREATE INDEX idx_rank_history_node ON mlm.rank_history (node_id);
|
||||
CREATE INDEX idx_rank_history_rank ON mlm.rank_history (rank_id);
|
||||
CREATE INDEX idx_rank_history_achieved ON mlm.rank_history (node_id, achieved_at DESC);
|
||||
Loading…
Reference in New Issue
Block a user