-- HOA LedgerIQ - Database Initialization -- Creates shared schema and base tables for multi-tenant architecture CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; CREATE EXTENSION IF NOT EXISTS "pgcrypto"; -- Shared schema for cross-tenant data CREATE SCHEMA IF NOT EXISTS shared; -- Organizations (HOAs) CREATE TABLE shared.organizations ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), name VARCHAR(255) NOT NULL, schema_name VARCHAR(63) NOT NULL UNIQUE, subdomain VARCHAR(63) UNIQUE, status VARCHAR(20) DEFAULT 'active' CHECK (status IN ('active', 'suspended', 'trial', 'archived')), settings JSONB DEFAULT '{}', contract_number VARCHAR(100), plan_level VARCHAR(50) DEFAULT 'standard' CHECK (plan_level IN ('standard', 'premium', 'enterprise')), address_line1 VARCHAR(255), address_line2 VARCHAR(255), city VARCHAR(100), state VARCHAR(2), zip_code VARCHAR(10), phone VARCHAR(20), email VARCHAR(255), tax_id VARCHAR(20), fiscal_year_start_month INTEGER DEFAULT 1 CHECK (fiscal_year_start_month BETWEEN 1 AND 12), payment_date DATE, confirmation_number VARCHAR(100), renewal_date DATE, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- Users (global, cross-tenant) CREATE TABLE shared.users ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), email VARCHAR(255) NOT NULL UNIQUE, password_hash VARCHAR(255), first_name VARCHAR(100), last_name VARCHAR(100), phone VARCHAR(20), is_email_verified BOOLEAN DEFAULT FALSE, mfa_enabled BOOLEAN DEFAULT FALSE, mfa_secret VARCHAR(255), oauth_provider VARCHAR(50), oauth_provider_id VARCHAR(255), last_login_at TIMESTAMPTZ, is_superadmin BOOLEAN DEFAULT FALSE, is_platform_owner BOOLEAN DEFAULT FALSE, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); -- User-Organization memberships with roles CREATE TABLE shared.user_organizations ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), user_id UUID NOT NULL REFERENCES shared.users(id) ON DELETE CASCADE, organization_id UUID NOT NULL REFERENCES shared.organizations(id) ON DELETE CASCADE, role VARCHAR(50) NOT NULL CHECK (role IN ('president', 'treasurer', 'secretary', 'member_at_large', 'manager', 'homeowner', 'admin', 'viewer')), is_active BOOLEAN DEFAULT TRUE, joined_at TIMESTAMPTZ DEFAULT NOW(), UNIQUE(user_id, organization_id) ); -- Invitations CREATE TABLE shared.invitations ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), organization_id UUID NOT NULL REFERENCES shared.organizations(id) ON DELETE CASCADE, email VARCHAR(255) NOT NULL, role VARCHAR(50) NOT NULL, invited_by UUID NOT NULL REFERENCES shared.users(id), token VARCHAR(255) NOT NULL UNIQUE, expires_at TIMESTAMPTZ NOT NULL, accepted_at TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT NOW() ); -- Market Rates (cross-tenant market data for investment recommendations) -- Supports CD, Money Market, and High Yield Savings rate types CREATE TABLE shared.cd_rates ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), bank_name VARCHAR(255) NOT NULL, apy DECIMAL(6,4) NOT NULL, min_deposit DECIMAL(15,2), term VARCHAR(100) NOT NULL, term_months INTEGER, rate_type VARCHAR(50) NOT NULL DEFAULT 'cd', fetched_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), source_url VARCHAR(500), created_at TIMESTAMPTZ DEFAULT NOW() ); -- Login history (track logins/org-switches for platform analytics) CREATE TABLE shared.login_history ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), user_id UUID NOT NULL REFERENCES shared.users(id) ON DELETE CASCADE, organization_id UUID REFERENCES shared.organizations(id) ON DELETE SET NULL, logged_in_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), ip_address VARCHAR(45), user_agent TEXT ); -- AI recommendation log (track AI usage per tenant) CREATE TABLE shared.ai_recommendation_log ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), tenant_schema VARCHAR(63), organization_id UUID REFERENCES shared.organizations(id) ON DELETE SET NULL, user_id UUID REFERENCES shared.users(id) ON DELETE SET NULL, recommendation_count INTEGER, response_time_ms INTEGER, status VARCHAR(20), requested_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- Indexes CREATE INDEX idx_user_orgs_user ON shared.user_organizations(user_id); CREATE INDEX idx_user_orgs_org ON shared.user_organizations(organization_id); CREATE INDEX idx_users_email ON shared.users(email); CREATE INDEX idx_orgs_schema ON shared.organizations(schema_name); CREATE INDEX idx_invitations_token ON shared.invitations(token); CREATE INDEX idx_invitations_email ON shared.invitations(email); CREATE INDEX idx_cd_rates_fetched ON shared.cd_rates(fetched_at DESC); CREATE INDEX idx_cd_rates_apy ON shared.cd_rates(apy DESC); CREATE INDEX idx_cd_rates_type ON shared.cd_rates(rate_type); CREATE INDEX idx_cd_rates_type_fetched ON shared.cd_rates(rate_type, fetched_at DESC); CREATE INDEX idx_login_history_org_time ON shared.login_history(organization_id, logged_in_at DESC); CREATE INDEX idx_login_history_user ON shared.login_history(user_id); CREATE INDEX idx_login_history_time ON shared.login_history(logged_in_at DESC); CREATE INDEX idx_ai_rec_log_org ON shared.ai_recommendation_log(organization_id); CREATE INDEX idx_ai_rec_log_time ON shared.ai_recommendation_log(requested_at DESC);