-- ===================================================== -- PORTFOLIO SCHEMA - PORTFOLIOS TABLE -- ===================================================== -- Description: User portfolios with asset allocations -- Schema: portfolio -- Author: Database Agent -- Date: 2026-01-25 -- ===================================================== CREATE TABLE portfolio.portfolios ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE, name VARCHAR(100) NOT NULL, description TEXT, risk_profile portfolio.risk_profile NOT NULL DEFAULT 'moderate', -- Portfolio values (updated by triggers/jobs) total_value DECIMAL(20, 8) NOT NULL DEFAULT 0, total_cost DECIMAL(20, 8) NOT NULL DEFAULT 0, unrealized_pnl DECIMAL(20, 8) NOT NULL DEFAULT 0, unrealized_pnl_percent DECIMAL(10, 4) NOT NULL DEFAULT 0, -- Statistics day_change_percent DECIMAL(10, 4) DEFAULT 0, week_change_percent DECIMAL(10, 4) DEFAULT 0, month_change_percent DECIMAL(10, 4) DEFAULT 0, all_time_change_percent DECIMAL(10, 4) DEFAULT 0, -- Metadata is_active BOOLEAN NOT NULL DEFAULT true, is_primary BOOLEAN NOT NULL DEFAULT false, last_rebalanced_at TIMESTAMPTZ, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- Indexes CREATE INDEX idx_portfolios_user_id ON portfolio.portfolios(user_id); CREATE INDEX idx_portfolios_risk_profile ON portfolio.portfolios(risk_profile); CREATE INDEX idx_portfolios_is_active ON portfolio.portfolios(is_active) WHERE is_active = true; -- Only one primary portfolio per user CREATE UNIQUE INDEX idx_portfolios_user_primary ON portfolio.portfolios(user_id) WHERE is_primary = true; -- Comments COMMENT ON TABLE portfolio.portfolios IS 'User investment portfolios with configurable allocations'; COMMENT ON COLUMN portfolio.portfolios.risk_profile IS 'User risk tolerance: conservative, moderate, aggressive'; COMMENT ON COLUMN portfolio.portfolios.total_value IS 'Current total value of all allocations in USD'; COMMENT ON COLUMN portfolio.portfolios.unrealized_pnl IS 'Unrealized profit/loss = total_value - total_cost'; COMMENT ON COLUMN portfolio.portfolios.is_primary IS 'Only one portfolio can be primary per user'; -- Trigger for updated_at CREATE OR REPLACE FUNCTION portfolio.update_portfolio_updated_at() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = NOW(); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_portfolios_updated_at BEFORE UPDATE ON portfolio.portfolios FOR EACH ROW EXECUTE FUNCTION portfolio.update_portfolio_updated_at();