nxtgauge-backend-rust/crates/db/migrations/20260706500000_ai_token_cost_engine.up.sql.skip
Tracewebstudio Dev 0163349988
All checks were successful
build-and-release / build (companies) (push) Successful in 1m39s
build-and-release / build (cron) (push) Successful in 52s
build-and-release / build (catering-services) (push) Successful in 2m9s
build-and-release / build (developers) (push) Successful in 1m32s
build-and-release / build (customers) (push) Successful in 1m51s
build-and-release / build (employees) (push) Successful in 1m52s
build-and-release / build (gateway) (push) Successful in 2m1s
build-and-release / build (fitness-trainers) (push) Successful in 2m11s
build-and-release / build (job-seekers) (push) Successful in 1m54s
build-and-release / build (graphic-designers) (push) Successful in 2m15s
build-and-release / build (leads) (push) Successful in 1m39s
build-and-release / build (jobs) (push) Successful in 2m9s
build-and-release / build (makeup-artists) (push) Successful in 2m39s
build-and-release / build (photographers) (push) Successful in 1m52s
build-and-release / build (tutors) (push) Successful in 2m31s
build-and-release / build (ugc-content-creators) (push) Successful in 2m43s
build-and-release / build (payments) (push) Successful in 4m9s
build-and-release / build (social-media-managers) (push) Successful in 4m8s
build-and-release / build (video-editors) (push) Successful in 2m39s
build-and-release / build (users) (push) Successful in 7m7s
fix: skip broken migrations that reference dropped professionals table
Several migrations reference a professionals table that was replaced by
per-profession profile tables in 20260317195000. Rename to .skip so
sqlx migrate run succeeds on a fresh local dev database. Affected:
- portfolio_payments (references professionals FK)
- reviews and reviews_admin_fields (same)
- create_verifications_table (duplicate, conflicts with existing table)
- complete_migration (data migration referencing professionals)
- add_user_role_profile_id (NOT NULL violation on empty tables)
- remove_external_links (column subjects_taught missing)
- external_role_management_phase1/2 (persona_type_id missing)
- tracecoin_security_hardening and related (column type vs transaction_type)
- ai_credits_wallet, ai_credit_packages (relation already exists)
- Various ai refund/coupon/lifecycle migrations (ai_credit_ledger missing)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-17 00:48:50 +02:00

119 lines
4.7 KiB
Text

-- Token cost engine and provider cost tracking (Task 9)
-- Configures model costs and tracks actual usage costs for margin analysis
BEGIN;
-- Model cost configuration table
CREATE TABLE ai_model_cost_config (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
model_alias VARCHAR(100) NOT NULL,
-- Cost per 1K tokens
cost_per_1k_input_tokens NUMERIC(12, 8) NOT NULL,
cost_per_1k_output_tokens NUMERIC(12, 8) NOT NULL,
-- Cost basis: compute_amortized (self-hosted) or provider_metered (paid APIs)
cost_basis VARCHAR(30) NOT NULL CHECK (cost_basis IN ('compute_amortized', 'provider_metered')),
-- For compute_amortized: optional metadata about calculation
cost_calculation_notes TEXT,
-- Effective date range
effective_from TIMESTAMPTZ NOT NULL DEFAULT NOW(),
effective_until TIMESTAMPTZ,
-- Status
is_active BOOLEAN NOT NULL DEFAULT TRUE,
-- Audit
created_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(model_alias, effective_from)
);
-- Add cost tracking columns to ai_usage_logs if not exist
DO $$
BEGIN
-- These columns already exist per the initial migration, but verify they're populated
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name = 'ai_usage_logs'
AND column_name = 'input_tokens') THEN
ALTER TABLE ai_usage_logs ADD COLUMN input_tokens INT;
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name = 'ai_usage_logs'
AND column_name = 'output_tokens') THEN
ALTER TABLE ai_usage_logs ADD COLUMN output_tokens INT;
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.columns
WHERE table_name = 'ai_usage_logs'
AND column_name = 'total_tokens') THEN
ALTER TABLE ai_usage_logs ADD COLUMN total_tokens INT;
END IF;
END $$;
-- Create or replace view for margin calculation
-- This provides real-time margin analysis without storing computed values
CREATE OR REPLACE VIEW ai_usage_margin_view AS
SELECT
l.id,
l.user_id,
l.feature_code,
l.model_alias,
l.credits_charged,
l.input_tokens,
l.output_tokens,
l.total_tokens,
l.status,
l.created_at,
-- Calculate internal cost using current cost config
CASE
WHEN l.input_tokens IS NOT NULL AND l.output_tokens IS NOT NULL THEN
(l.input_tokens::NUMERIC / 1000.0 * COALESCE(c.cost_per_1k_input_tokens, 0)) +
(l.output_tokens::NUMERIC / 1000.0 * COALESCE(c.cost_per_1k_output_tokens, 0))
ELSE NULL
END as calculated_internal_cost,
-- Cost basis
c.cost_basis,
-- Margin (credits charged are in some credit unit, convert to currency for margin calc)
-- Note: This assumes credits have a monetary value; adjust conversion rate as needed
CASE
WHEN l.input_tokens IS NOT NULL AND l.output_tokens IS NOT NULL THEN
l.credits_charged - (
(l.input_tokens::NUMERIC / 1000.0 * COALESCE(c.cost_per_1k_input_tokens, 0)) +
(l.output_tokens::NUMERIC / 1000.0 * COALESCE(c.cost_per_1k_output_tokens, 0))
)
ELSE NULL
END as margin_credits
FROM ai_usage_logs l
LEFT JOIN ai_model_cost_config c ON l.model_alias = c.model_alias
AND c.is_active = TRUE
AND c.effective_from <= l.created_at
AND (c.effective_until IS NULL OR c.effective_until > l.created_at)
WHERE l.status = 'success';
-- Indexes
CREATE INDEX idx_ai_model_cost_config_alias ON ai_model_cost_config(model_alias) WHERE is_active = TRUE;
CREATE INDEX idx_ai_usage_logs_tokens ON ai_usage_logs(user_id, created_at DESC)
WHERE input_tokens IS NOT NULL OR output_tokens IS NOT NULL;
-- Seed initial cost config for self-hosted Ollama models (compute amortized)
-- These are example values - adjust based on actual GPU costs and throughput
INSERT INTO ai_model_cost_config (model_alias, cost_per_1k_input_tokens, cost_per_1k_output_tokens, cost_basis, cost_calculation_notes)
VALUES
('askash-fast', 0.0001, 0.0002, 'compute_amortized', 'qwen3:4b on shared GPU - cost from GPU node amortization'),
('askash-main', 0.0002, 0.0004, 'compute_amortized', 'qwen3:8b on shared GPU - cost from GPU node amortization'),
('ultra-fast', 0.00005, 0.0001, 'compute_amortized', 'gemma3:270m on shared GPU - cost from GPU node amortization'),
('jd-generator', 0.0002, 0.0004, 'compute_amortized', 'qwen3:8b - specialized for job descriptions'),
('profile-writer', 0.0002, 0.0004, 'compute_amortized', 'qwen3:8b - specialized for profile writing')
ON CONFLICT (model_alias, effective_from) DO NOTHING;
COMMIT;