-- ============================================= -- 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';