feat: add ai_user_daily_spend table and queries (#26562)

## Description

Adds the spend tracking table and queries needed by [AIGOV-427](https://linear.app/codercom/issue/AIGOV-427/add-post-response-spend-accumulation) (post-response accumulation) and [AIGOV-428](https://linear.app/codercom/issue/AIGOV-428/add-pre-request-budget-enforcement) (pre-request enforcement).

## Changes

- Add `ai_user_daily_spend` table to aggregate per-user, per-effective-group AI spend by UTC day.
- Add `UpsertUserAIDailySpend` and `GetUserAISpendSince` queries.

Closes https://linear.app/codercom/issue/AIGOV-426/add-daily-spend-table-and-queries

> [!NOTE]
> Initially generated by Claude Opus 4.7, modified and reviewed by @ssncferreira
This commit is contained in:
Susana Ferreira
2026-07-02 16:29:25 +01:00
committed by GitHub
parent dee41c34e6
commit fcdd029d74
15 changed files with 613 additions and 0 deletions
+23
View File
@@ -1517,6 +1517,24 @@ CREATE TABLE ai_seat_state (
updated_at timestamp with time zone NOT NULL
);
CREATE TABLE ai_user_daily_spend (
user_id uuid NOT NULL,
effective_group_id uuid NOT NULL,
day date NOT NULL,
spend_micros bigint NOT NULL,
CONSTRAINT ai_user_daily_spend_spend_micros_check CHECK ((spend_micros >= 0))
);
COMMENT ON TABLE ai_user_daily_spend IS 'Daily AI spend per user and effective group.';
COMMENT ON COLUMN ai_user_daily_spend.user_id IS 'The user who incurred the spend.';
COMMENT ON COLUMN ai_user_daily_spend.effective_group_id IS 'The group this spend is attributed to for budget purposes.';
COMMENT ON COLUMN ai_user_daily_spend.day IS 'UTC calendar day the spend was incurred.';
COMMENT ON COLUMN ai_user_daily_spend.spend_micros IS 'Accumulated spend in micro-units (1 unit = 1,000,000).';
CREATE TABLE aibridge_interceptions (
id uuid NOT NULL,
initiator_id uuid NOT NULL,
@@ -4120,6 +4138,9 @@ ALTER TABLE ONLY ai_providers
ALTER TABLE ONLY ai_seat_state
ADD CONSTRAINT ai_seat_state_pkey PRIMARY KEY (user_id);
ALTER TABLE ONLY ai_user_daily_spend
ADD CONSTRAINT ai_user_daily_spend_pkey PRIMARY KEY (user_id, effective_group_id, day);
ALTER TABLE ONLY aibridge_interceptions
ADD CONSTRAINT aibridge_interceptions_pkey PRIMARY KEY (id);
@@ -4526,6 +4547,8 @@ CREATE INDEX idx_ai_provider_keys_provider_id ON ai_provider_keys USING btree (p
CREATE INDEX idx_ai_providers_enabled ON ai_providers USING btree (enabled) WHERE (deleted = false);
CREATE INDEX idx_ai_user_daily_spend_effective_group_id_day ON ai_user_daily_spend USING btree (effective_group_id, day);
CREATE INDEX idx_aibridge_interceptions_agent_firewall_session_id ON aibridge_interceptions USING btree (agent_firewall_session_id) WHERE (agent_firewall_session_id IS NOT NULL);
CREATE INDEX idx_aibridge_interceptions_client ON aibridge_interceptions USING btree (client);