Files
2026-06-14 15:34:13 +08:00

79 lines
3.9 KiB
SQL

CREATE TABLE IF NOT EXISTS hwlab_billing_plans (
id TEXT PRIMARY KEY,
display_name TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'active',
description TEXT NOT NULL DEFAULT '',
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
CHECK (status IN ('active', 'disabled'))
);
INSERT INTO hwlab_billing_plans (id, display_name, status, description, metadata)
VALUES ('default', 'Default', 'active', 'Default HWLAB v0.3 resource plan', '{"source":"hwlab-v03","limitSemantics":"zero-means-unlimited"}'::jsonb)
ON CONFLICT (id) DO UPDATE SET
display_name = EXCLUDED.display_name,
status = EXCLUDED.status,
description = EXCLUDED.description,
metadata = hwlab_billing_plans.metadata || EXCLUDED.metadata,
updated_at = now();
CREATE TABLE IF NOT EXISTS hwlab_resource_entitlements (
id TEXT PRIMARY KEY,
plan_id TEXT NOT NULL REFERENCES hwlab_billing_plans(id) ON DELETE CASCADE,
resource_type TEXT NOT NULL,
enabled BOOLEAN NOT NULL DEFAULT TRUE,
monthly_quota_credits BIGINT NOT NULL DEFAULT 0,
max_concurrent_reservations INTEGER NOT NULL DEFAULT 0,
rpm_limit INTEGER NOT NULL DEFAULT 0,
metadata JSONB NOT NULL DEFAULT '{}'::jsonb,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
UNIQUE (plan_id, resource_type),
CHECK (resource_type <> ''),
CHECK (monthly_quota_credits >= 0),
CHECK (max_concurrent_reservations >= 0),
CHECK (rpm_limit >= 0)
);
CREATE INDEX IF NOT EXISTS hwlab_resource_entitlements_plan_idx ON hwlab_resource_entitlements(plan_id);
CREATE INDEX IF NOT EXISTS hwlab_resource_entitlements_resource_idx ON hwlab_resource_entitlements(resource_type);
INSERT INTO hwlab_resource_entitlements (id, plan_id, resource_type, enabled, monthly_quota_credits, max_concurrent_reservations, rpm_limit, metadata)
VALUES
('ent_default_code_agent', 'default', 'code_agent', TRUE, 0, 0, 0, '{"serviceIds":["hwlab-code-agent"],"limitSemantics":"zero-means-unlimited"}'::jsonb),
('ent_default_aipod', 'default', 'aipod', TRUE, 0, 0, 0, '{"serviceIds":["hwlab-aipod"],"limitSemantics":"zero-means-unlimited"}'::jsonb),
('ent_default_hwpod', 'default', 'hwpod', TRUE, 0, 0, 0, '{"serviceIds":["hwlab-hwpod"],"limitSemantics":"zero-means-unlimited"}'::jsonb)
ON CONFLICT (plan_id, resource_type) DO UPDATE SET
enabled = EXCLUDED.enabled,
monthly_quota_credits = EXCLUDED.monthly_quota_credits,
max_concurrent_reservations = EXCLUDED.max_concurrent_reservations,
rpm_limit = EXCLUDED.rpm_limit,
metadata = hwlab_resource_entitlements.metadata || EXCLUDED.metadata,
updated_at = now();
ALTER TABLE hwlab_billing_reservations ADD COLUMN IF NOT EXISTS resource_type TEXT NOT NULL DEFAULT 'generic';
ALTER TABLE hwlab_usage_records ADD COLUMN IF NOT EXISTS resource_type TEXT NOT NULL DEFAULT 'generic';
UPDATE hwlab_billing_reservations
SET resource_type = CASE
WHEN lower(service_id) LIKE '%code-agent%' OR lower(service_id) LIKE '%code_agent%' THEN 'code_agent'
WHEN lower(service_id) LIKE '%aipod%' THEN 'aipod'
WHEN lower(service_id) LIKE '%hwpod%' THEN 'hwpod'
ELSE resource_type
END
WHERE resource_type = 'generic';
UPDATE hwlab_usage_records
SET resource_type = CASE
WHEN lower(service_id) LIKE '%code-agent%' OR lower(service_id) LIKE '%code_agent%' THEN 'code_agent'
WHEN lower(service_id) LIKE '%aipod%' THEN 'aipod'
WHEN lower(service_id) LIKE '%hwpod%' THEN 'hwpod'
ELSE resource_type
END
WHERE resource_type = 'generic';
CREATE INDEX IF NOT EXISTS hwlab_billing_reservations_user_resource_idx ON hwlab_billing_reservations(user_id, resource_type, status, expires_at);
CREATE INDEX IF NOT EXISTS hwlab_billing_reservations_user_resource_created_idx ON hwlab_billing_reservations(user_id, resource_type, created_at);
CREATE INDEX IF NOT EXISTS hwlab_usage_records_user_resource_created_idx ON hwlab_usage_records(user_id, resource_type, created_at);