-- +goose Up -- Users CREATE TABLE IF NOT EXISTS users ( id BIGSERIAL PRIMARY KEY, username VARCHAR(255) NOT NULL UNIQUE, password VARCHAR(255) NOT NULL, roles TEXT[] DEFAULT '{user}', status VARCHAR(50) DEFAULT 'active', metas JSONB DEFAULT '{}', balance BIGINT DEFAULT 0, balance_frozen BIGINT DEFAULT 0, verified_at TIMESTAMP WITH TIME ZONE, -- New fields nickname VARCHAR(255) DEFAULT '', avatar VARCHAR(512) DEFAULT '', gender VARCHAR(32) DEFAULT 'secret', bio VARCHAR(512) DEFAULT '', birthday DATE, location JSONB DEFAULT '{}', points BIGINT DEFAULT 0, phone VARCHAR(32) DEFAULT '', is_real_name_verified BOOLEAN DEFAULT FALSE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), deleted_at TIMESTAMP WITH TIME ZONE ); -- Tenants CREATE TABLE IF NOT EXISTS tenants ( id BIGSERIAL PRIMARY KEY, user_id BIGINT NOT NULL, code VARCHAR(64) NOT NULL UNIQUE, uuid UUID NOT NULL, name VARCHAR(128) NOT NULL, status VARCHAR(64) NOT NULL, config JSONB DEFAULT '{}', expired_at TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_tenants_user_id ON tenants(user_id); -- TenantUsers CREATE TABLE IF NOT EXISTS tenant_users ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL, user_id BIGINT NOT NULL, role TEXT[] DEFAULT '{member}', status VARCHAR(50) DEFAULT 'verified', created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), UNIQUE(tenant_id, user_id) ); -- Contents CREATE TABLE IF NOT EXISTS contents ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL, user_id BIGINT NOT NULL, title VARCHAR(255) NOT NULL, description TEXT NOT NULL, status VARCHAR(32) DEFAULT 'draft', visibility VARCHAR(32) DEFAULT 'tenant_only', preview_seconds INT DEFAULT 60, preview_downloadable BOOLEAN DEFAULT FALSE, published_at TIMESTAMP WITH TIME ZONE, summary VARCHAR(256) DEFAULT '', tags JSONB DEFAULT '[]', -- New fields body TEXT DEFAULT '', genre VARCHAR(64) DEFAULT '', views INT DEFAULT 0, likes INT DEFAULT 0, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), deleted_at TIMESTAMP WITH TIME ZONE ); CREATE INDEX IF NOT EXISTS idx_contents_tenant_id ON contents(tenant_id); -- MediaAssets CREATE TABLE IF NOT EXISTS media_assets ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL, user_id BIGINT NOT NULL, type VARCHAR(32) DEFAULT 'video', status VARCHAR(32) DEFAULT 'uploaded', provider VARCHAR(64) NOT NULL, bucket VARCHAR(128) NOT NULL, object_key VARCHAR(512) NOT NULL, meta JSONB DEFAULT '{}', variant VARCHAR(32) DEFAULT 'main', source_asset_id BIGINT DEFAULT 0, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), deleted_at TIMESTAMP WITH TIME ZONE ); -- ContentAssets CREATE TABLE IF NOT EXISTS content_assets ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL, user_id BIGINT NOT NULL, content_id BIGINT NOT NULL, asset_id BIGINT NOT NULL, role VARCHAR(32) DEFAULT 'main', sort INT DEFAULT 0, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- ContentPrices CREATE TABLE IF NOT EXISTS content_prices ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL, user_id BIGINT NOT NULL, content_id BIGINT NOT NULL, currency VARCHAR(16) DEFAULT 'CNY', price_amount BIGINT NOT NULL, discount_type VARCHAR(16) DEFAULT 'none', discount_value BIGINT DEFAULT 0, discount_start_at TIMESTAMP WITH TIME ZONE, discount_end_at TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), UNIQUE(tenant_id, content_id) ); -- ContentAccess CREATE TABLE IF NOT EXISTS content_access ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL, user_id BIGINT NOT NULL, content_id BIGINT NOT NULL, order_id BIGINT DEFAULT 0, status VARCHAR(16) DEFAULT 'active', revoked_at TIMESTAMP WITH TIME ZONE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), UNIQUE(tenant_id, user_id, content_id) ); -- Orders CREATE TABLE IF NOT EXISTS orders ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL, user_id BIGINT NOT NULL, type VARCHAR(32) DEFAULT 'content_purchase', status VARCHAR(32) DEFAULT 'created', currency VARCHAR(16) DEFAULT 'CNY', amount_original BIGINT NOT NULL, amount_discount BIGINT NOT NULL, amount_paid BIGINT NOT NULL, snapshot JSONB DEFAULT '{}', idempotency_key VARCHAR(128) NOT NULL, paid_at TIMESTAMP WITH TIME ZONE, refunded_at TIMESTAMP WITH TIME ZONE, refund_forced BOOLEAN DEFAULT FALSE, refund_operator_user_id BIGINT DEFAULT 0, refund_reason VARCHAR(255) DEFAULT '', created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- OrderItems CREATE TABLE IF NOT EXISTS order_items ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL, user_id BIGINT NOT NULL, order_id BIGINT NOT NULL, content_id BIGINT NOT NULL, content_user_id BIGINT NOT NULL, amount_paid BIGINT NOT NULL, snapshot JSONB DEFAULT '{}', created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- TenantLedgers CREATE TABLE IF NOT EXISTS tenant_ledgers ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL, user_id BIGINT NOT NULL, order_id BIGINT DEFAULT 0, type VARCHAR(32) NOT NULL, amount BIGINT NOT NULL, balance_before BIGINT NOT NULL, balance_after BIGINT NOT NULL, frozen_before BIGINT NOT NULL, frozen_after BIGINT NOT NULL, idempotency_key VARCHAR(128) NOT NULL, remark VARCHAR(255) NOT NULL, operator_user_id BIGINT DEFAULT 0, biz_ref_type VARCHAR(32) DEFAULT '', biz_ref_id BIGINT DEFAULT 0, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- TenantInvites CREATE TABLE IF NOT EXISTS tenant_invites ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL, user_id BIGINT NOT NULL, code VARCHAR(64) NOT NULL, status VARCHAR(32) DEFAULT 'active', max_uses INT NOT NULL, used_count INT DEFAULT 0, expires_at TIMESTAMP WITH TIME ZONE, disabled_at TIMESTAMP WITH TIME ZONE, disabled_operator_user_id BIGINT DEFAULT 0, remark VARCHAR(255) DEFAULT '', created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- TenantJoinRequests CREATE TABLE IF NOT EXISTS tenant_join_requests ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL, user_id BIGINT NOT NULL, status VARCHAR(32) DEFAULT 'pending', reason VARCHAR(255) NOT NULL, decided_at TIMESTAMP WITH TIME ZONE, decided_operator_user_id BIGINT DEFAULT 0, decided_reason VARCHAR(255) DEFAULT '', created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- Comments CREATE TABLE IF NOT EXISTS comments ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL, user_id BIGINT NOT NULL, content_id BIGINT NOT NULL, reply_to BIGINT DEFAULT 0, content TEXT NOT NULL, likes INT DEFAULT 0, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), deleted_at TIMESTAMP WITH TIME ZONE ); CREATE INDEX IF NOT EXISTS idx_comments_content_id ON comments(content_id); CREATE INDEX IF NOT EXISTS idx_comments_user_id ON comments(user_id); -- User Content Actions (Like, Favorite) CREATE TABLE IF NOT EXISTS user_content_actions ( id BIGSERIAL PRIMARY KEY, user_id BIGINT NOT NULL, content_id BIGINT NOT NULL, type VARCHAR(32) NOT NULL, -- like, favorite created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), UNIQUE(user_id, content_id, type) ); -- User Comment Actions (Like) CREATE TABLE IF NOT EXISTS user_comment_actions ( id BIGSERIAL PRIMARY KEY, user_id BIGINT NOT NULL, comment_id BIGINT NOT NULL, type VARCHAR(32) NOT NULL, -- like created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), UNIQUE(user_id, comment_id, type) ); -- Payout Accounts CREATE TABLE IF NOT EXISTS payout_accounts ( id BIGSERIAL PRIMARY KEY, tenant_id BIGINT NOT NULL, -- Associated with a creator tenant user_id BIGINT NOT NULL, -- Creator user type VARCHAR(32) NOT NULL, -- bank, alipay name VARCHAR(128) NOT NULL, account VARCHAR(128) NOT NULL, realname VARCHAR(128) NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(), updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_payout_accounts_tenant_id ON payout_accounts(tenant_id); -- Notifications CREATE TABLE IF NOT EXISTS notifications ( id BIGSERIAL PRIMARY KEY, user_id BIGINT NOT NULL, tenant_id BIGINT DEFAULT 0, -- Optional source tenant type VARCHAR(32) NOT NULL, -- system, order, audit, interaction title VARCHAR(255) NOT NULL, content TEXT NOT NULL, is_read BOOLEAN DEFAULT FALSE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); CREATE INDEX IF NOT EXISTS idx_notifications_user_id ON notifications(user_id); -- +goose Down -- Revert logic omitted for dev speed in this context