template-saas/apps/database/ddl/schemas/ai/tables/02-ai-usage.sql
rckrdmrd 68d3c54023 docs(ai): Update documentation and fix DDL scripts
Documentation:
- Update SAAS-006-ai-integration.md with full implementation details
- Update _MAP.md with AI schema (30 tables, 11 schemas)
- Update PROJECT-STATUS.md (67% completion)

Database fixes:
- Add update_updated_at_column() function to 03-functions.sql
- Add trigger creation for ai.configs in 03-functions.sql
- Fix partial index in 02-ai-usage.sql (remove CURRENT_DATE)
- Add AI schema grants to create-database.sh
- Add AI to SCHEMA_ORDER array

Validated: Database recreation successful with all AI objects

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 07:21:56 -06:00

125 lines
4.3 KiB
PL/PgSQL

-- ============================================
-- AI Usage Tracking Table
-- Records each AI API call for billing/analytics
-- ============================================
CREATE TABLE ai.usage (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users.users(id) ON DELETE CASCADE,
-- Request details
provider ai.ai_provider NOT NULL,
model VARCHAR(100) NOT NULL,
model_type ai.ai_model_type NOT NULL DEFAULT 'chat',
status ai.usage_status NOT NULL DEFAULT 'pending',
-- Token counts
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
total_tokens INTEGER GENERATED ALWAYS AS (input_tokens + output_tokens) STORED,
-- Cost tracking (in USD, 6 decimal precision)
cost_input NUMERIC(12,6) NOT NULL DEFAULT 0,
cost_output NUMERIC(12,6) NOT NULL DEFAULT 0,
cost_total NUMERIC(12,6) GENERATED ALWAYS AS (cost_input + cost_output) STORED,
-- Performance metrics
latency_ms INTEGER,
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
completed_at TIMESTAMPTZ,
-- Request metadata
request_id VARCHAR(100),
endpoint VARCHAR(50),
error_message TEXT,
-- Additional context
metadata JSONB DEFAULT '{}',
-- Timestamps
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Indexes for common queries
CREATE INDEX idx_ai_usage_tenant ON ai.usage(tenant_id);
CREATE INDEX idx_ai_usage_user ON ai.usage(user_id);
CREATE INDEX idx_ai_usage_tenant_created ON ai.usage(tenant_id, created_at DESC);
CREATE INDEX idx_ai_usage_model ON ai.usage(model);
CREATE INDEX idx_ai_usage_status ON ai.usage(status);
CREATE INDEX idx_ai_usage_created_at ON ai.usage(created_at DESC);
-- Index for monthly queries (used by get_current_month_usage function)
-- Note: Partial index with CURRENT_DATE removed as it's not IMMUTABLE
CREATE INDEX idx_ai_usage_monthly ON ai.usage(tenant_id, created_at, status)
WHERE status = 'completed';
-- RLS
ALTER TABLE ai.usage ENABLE ROW LEVEL SECURITY;
CREATE POLICY ai_usage_tenant_isolation ON ai.usage
FOR ALL
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
-- Comments
COMMENT ON TABLE ai.usage IS 'AI API usage tracking for billing and analytics';
COMMENT ON COLUMN ai.usage.input_tokens IS 'Number of input/prompt tokens';
COMMENT ON COLUMN ai.usage.output_tokens IS 'Number of output/completion tokens';
COMMENT ON COLUMN ai.usage.cost_input IS 'Cost for input tokens in USD';
COMMENT ON COLUMN ai.usage.cost_output IS 'Cost for output tokens in USD';
COMMENT ON COLUMN ai.usage.latency_ms IS 'Request latency in milliseconds';
-- ============================================
-- Monthly Usage Summary View
-- For efficient billing queries
-- ============================================
CREATE VIEW ai.monthly_usage AS
SELECT
tenant_id,
date_trunc('month', created_at) AS month,
COUNT(*) AS request_count,
SUM(input_tokens) AS total_input_tokens,
SUM(output_tokens) AS total_output_tokens,
SUM(input_tokens + output_tokens) AS total_tokens,
SUM(cost_input + cost_output) AS total_cost,
AVG(latency_ms) AS avg_latency_ms
FROM ai.usage
WHERE status = 'completed'
GROUP BY tenant_id, date_trunc('month', created_at);
COMMENT ON VIEW ai.monthly_usage IS 'Monthly AI usage aggregation per tenant';
-- ============================================
-- Function: Get tenant usage for current month
-- ============================================
CREATE OR REPLACE FUNCTION ai.get_current_month_usage(p_tenant_id UUID)
RETURNS TABLE (
request_count BIGINT,
total_input_tokens BIGINT,
total_output_tokens BIGINT,
total_tokens BIGINT,
total_cost NUMERIC,
avg_latency_ms NUMERIC
) AS $$
BEGIN
RETURN QUERY
SELECT
COUNT(*)::BIGINT,
COALESCE(SUM(input_tokens), 0)::BIGINT,
COALESCE(SUM(output_tokens), 0)::BIGINT,
COALESCE(SUM(input_tokens + output_tokens), 0)::BIGINT,
COALESCE(SUM(cost_input + cost_output), 0)::NUMERIC,
COALESCE(AVG(latency_ms), 0)::NUMERIC
FROM ai.usage
WHERE tenant_id = p_tenant_id
AND status = 'completed'
AND created_at >= date_trunc('month', CURRENT_DATE);
END;
$$ LANGUAGE plpgsql STABLE;
COMMENT ON FUNCTION ai.get_current_month_usage IS 'Get AI usage for current month for a tenant';