chore: resolve pr 377 checks

This commit is contained in:
fawney19
2026-05-06 02:22:32 +08:00
502 changed files with 89553 additions and 21893 deletions

View File

@@ -5,6 +5,7 @@ edition.workspace = true
license.workspace = true
repository.workspace = true
description = "Shared data access contracts and config for Aether Rust services"
build = "build.rs"
[dependencies]
aether-ai-formats.workspace = true
@@ -13,6 +14,7 @@ aether-cache.workspace = true
aether-wallet.workspace = true
async-trait.workspace = true
chrono.workspace = true
chrono-tz.workspace = true
futures-util.workspace = true
flate2.workspace = true
redis.workspace = true

View File

@@ -0,0 +1,158 @@
# aether-data
`aether-data` is the runtime data-access crate. It owns concrete database and
Redis clients, concrete repository implementations, migration/backfill/export
workflows, and the composition layer that wires those pieces into the rest of
the application.
It does not own the cross-crate DTO contracts. Shared repository records and
errors that are consumed by scheduler, billing, admin, usage runtime, and video
task crates live in `../aether-data-contracts`.
## Directory Map
| Path | Responsibility |
|---|---|
| `src/database.rs` | Logical SQL driver selection and shared pool configuration. |
| `src/config.rs` | Data-layer config that combines SQL and Redis settings. |
| `src/maintenance.rs` | Maintenance DTOs and aggregation summaries used by backend dispatch and runtime maintenance entrypoints. |
| `src/driver/{postgres,mysql,sqlite}` | Low-level SQL driver primitives such as pools, transactions, and leases. These modules should not contain domain repository logic. |
| `src/driver/redis` | Low-level Redis clients, locks, streams, and namespaces. |
| `src/repository` | Domain repository traits/types re-exported from contracts plus concrete in-memory/Postgres/MySQL/SQLite implementations. |
| `src/backend` | Composition root. Builds concrete driver backends and exposes app-facing read/write/worker/lock/lease handles. |
| `src/backend/{maintenance,stats,wallet,system}.rs` | Backend-owned maintenance, aggregation, wallet ledger, and system config workflows that are not normal request-path repositories. |
| `src/lifecycle/migrate.rs` and `src/lifecycle/migrate/*` | Runtime migration entry points and migration-specific tests/helpers. |
| `src/lifecycle/backfill.rs` | Backfill entry points and backfill discovery. |
| `src/lifecycle/export.rs` | Cross-database export/import workflows. |
| `migrations/{postgres,mysql,sqlite}` | Executable `sqlx` migrations embedded at compile time. |
| `schema` | Schema maintenance workspace for logical definitions, driver fragments, and generated output. |
| `schema/logical` | Human-maintained logical table definitions used by `aether-data-schema`. |
| `schema/drivers/{postgres,mysql,sqlite}` | Human-maintained driver fragments that compose back into executable SQL while generation is being promoted. |
| `schema/bootstrap/postgres` | Human-maintained source fragments for the Postgres bootstrap snapshot. `build.rs` composes them into the runtime embedded artifact during crate builds. |
| `schema/generated` | Machine-written SQL generated from logical schema for audit and drift detection only. |
| `schema/overrides` | Rare driver-specific SQL escape hatch. Keep README-only until a real override is needed. |
| `backfills/{postgres,mysql,sqlite}` | Executable backfill SQL grouped by driver. |
## Layering Rules
The crate is easiest to read as five layers:
1. Contracts: DTOs, input structs, repository traits, and `DataLayerError`.
Prefer `aether-data-contracts` for anything that another crate needs to
compile against.
2. Driver primitives: `driver/postgres`, `driver/mysql`, `driver/sqlite`, and
`driver/redis` connect to
infrastructure and expose pools/runners.
3. Repository implementations: `repository/<domain>/{sql,mysql,sqlite,memory}`
translate contract types to driver-specific SQL.
4. Backend composition: `backend` chooses one SQL driver from config and wires
repository implementations into app-facing handles. Backend-owned runtime
maintenance workflows live in focused backend modules rather than in the
driver pool files.
5. Maintenance workflows: `lifecycle/migrate`, `lifecycle/backfill`,
`lifecycle/export`, and `schema` manage database lifecycle outside normal
request handling.
Do not add domain queries to low-level pool modules. Do not add driver selection
logic inside individual repository implementations. Keep cross-crate contracts
out of `aether-data` unless they are implementation-only.
## Repository Layout
Most domain repositories use this shape:
```text
src/repository/<domain>/
mod.rs # exports trait/type names and concrete implementations
types.rs # implementation-local DTOs when they are not already in contracts
postgres.rs # Postgres implementation
mysql.rs # MySQL implementation
sqlite.rs # SQLite implementation
memory.rs # tests/dev in-memory implementation
```
Use explicit driver filenames for repository implementations. Do not introduce
new generic `sql.rs` modules for driver-specific code.
## SQL Driver Policy
The project supports three SQL drivers at the repository/backend boundary:
Postgres, MySQL, and SQLite. That does not mean every raw SQL file is shared.
The portable contract is the Rust shape and behavior; the physical SQL stays
driver-specific where syntax, indexes, JSON support, timestamps, locking, or
upsert semantics differ.
Use logical types in design docs and reviews:
| Logical type | Postgres | MySQL | SQLite |
|---|---|---|---|
| `json` | `json` or `jsonb` | `json` or text JSON | text JSON |
| `bool` | `boolean` | `boolean` / `tinyint(1)` | integer |
| `time_unix` | `bigint` or legacy timestamp | `bigint` | integer |
| `money_decimal` | `numeric` / legacy double | `double` | real |
`jsonb` is acceptable only in Postgres SQL. MySQL and SQLite migrations must not
contain `jsonb`; this is guarded by migration tests. Prefer `serde_json::Value`
or typed Rust structs at the repository boundary so callers do not depend on the
physical storage type.
## Schema Maintenance
Executable migrations stay under `migrations/{postgres,mysql,sqlite}` because
`sqlx::migrate!` embeds those paths and existing deployments record those file
versions.
The large baseline SQL files are maintained through `schema` fragments. New
table-structure work should start in `schema/logical/*.toml` and be generated
into driver-specific SQL before it is composed into executable migrations:
```bash
bash crates/aether-data/schema/compose_schema.sh generate
bash crates/aether-data/schema/compose_schema.sh compose
bash crates/aether-data/schema/compose_schema.sh check
```
`schema/generated/**` is machine-written by `aether-data-schema`; it is checked
in to make generator drift reviewable, not because runtime reads it. Edit
`schema/logical/*.toml` instead. Use `schema/overrides/**` only as an exception
bucket for driver-specific SQL that cannot live cleanly in logical schema or the
normal driver fragments.
`compose_schema.sh check` also verifies that required baseline/portable
table-creation SQL is represented in `schema/logical`. This is the guardrail
that keeps table structure from drifting back into three manually maintained
definitions.
For executable fragments that have not been promoted to generated output yet,
edit fragments under `schema/drivers/{postgres,mysql,sqlite}` directly, run
`compose`, then run `check`. Do not edit baseline executable SQL and fragments
independently.
When adding a table:
1. Add or update `schema/logical/*.toml` first for the table structure.
2. Run `schema/compose_schema.sh generate` and inspect the generated driver SQL.
3. Add or update the executable driver-specific migration/fragments only for
deployment compatibility or generator gaps.
4. Add or update repository contracts in `aether-data-contracts` if other crates
need the new shape.
5. Add driver repository implementations only for the drivers that are actually
supported for that domain.
6. Wire new repositories through `src/backend/read.rs` or `src/backend/write.rs`
only after the implementation exists for each selected driver.
7. Update `docs/architecture/data-schema-inventory.md` for new tables or logical
type changes.
## Known Cleanup Targets
These are intentionally staged to keep the multi-database refactor reviewable:
1. Group repository domains once file-level names are stable. Likely groups:
identity, auth config, provider catalog, runtime tasks, wallet/billing,
usage, stats, and proxy nodes.
2. Continue shrinking Postgres stats SQL modules where useful by moving shared
SQL fragments and row-mapping helpers behind focused `backend/stats/*`
modules.
3. Consider a later crate split only after module boundaries are stable. The
likely split is schema/migration tooling versus runtime repository backends,
not an ORM rewrite.

View File

@@ -0,0 +1 @@
MySQL-specific backfills live here when they are needed.

View File

@@ -0,0 +1 @@
SQLite-specific backfills live here when they are needed.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
use std::env;
use std::error::Error;
use std::fs;
use std::path::PathBuf;
fn main() {
if let Err(err) = build_empty_database_snapshot() {
panic!("failed to build empty database snapshot: {err}");
}
}
fn build_empty_database_snapshot() -> Result<(), Box<dyn Error>> {
let manifest = manifest_path();
let source_root = manifest.parent().ok_or_else(|| {
std::io::Error::other("bootstrap manifest should have a parent directory")
})?;
let output = out_dir()?.join("empty_database_snapshot.sql");
println!("cargo:rerun-if-changed={}", manifest.display());
let mut snapshot = Vec::new();
let manifest_source = fs::read_to_string(&manifest)?;
for part in manifest_source.lines().map(str::trim) {
if part.is_empty() || part.starts_with('#') {
continue;
}
let fragment = source_root.join(part);
println!("cargo:rerun-if-changed={}", fragment.display());
snapshot.extend_from_slice(&fs::read(&fragment)?);
}
fs::write(output, snapshot)?;
Ok(())
}
fn manifest_path() -> PathBuf {
PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR should be set"))
.join("schema/bootstrap/postgres/manifest.txt")
}
fn out_dir() -> Result<PathBuf, Box<dyn Error>> {
Ok(PathBuf::from(env::var("OUT_DIR").map_err(|_| {
std::io::Error::other("OUT_DIR should be set")
})?))
}

View File

@@ -0,0 +1,791 @@
CREATE TABLE IF NOT EXISTS users (
id VARCHAR(64) PRIMARY KEY,
external_id VARCHAR(255),
email VARCHAR(320),
username VARCHAR(255),
password_hash VARCHAR(255),
role VARCHAR(64),
auth_source VARCHAR(64) NOT NULL DEFAULT 'local',
email_verified TINYINT(1) NOT NULL DEFAULT 0,
is_active TINYINT(1) NOT NULL DEFAULT 1,
is_deleted TINYINT(1) NOT NULL DEFAULT 0,
allowed_models TEXT,
allowed_providers TEXT,
allowed_api_formats TEXT,
model_capability_settings TEXT,
rate_limit INT,
metadata TEXT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
last_login_at BIGINT,
UNIQUE KEY users_email_key (email),
UNIQUE KEY users_username_key (username)
);
CREATE TABLE IF NOT EXISTS api_keys (
id VARCHAR(64) PRIMARY KEY,
user_id VARCHAR(64) NOT NULL,
key_hash VARCHAR(255) NOT NULL,
key_encrypted TEXT,
name VARCHAR(255),
key_prefix VARCHAR(64),
status VARCHAR(64) NOT NULL DEFAULT 'active',
allowed_models TEXT,
allowed_providers TEXT,
allowed_api_formats TEXT,
rate_limit INT DEFAULT 100,
concurrent_limit INT,
force_capabilities TEXT,
is_active TINYINT(1) NOT NULL DEFAULT 1,
is_locked TINYINT(1) NOT NULL DEFAULT 0,
is_standalone TINYINT(1) NOT NULL DEFAULT 0,
auto_delete_on_expiry TINYINT(1) NOT NULL DEFAULT 0,
total_requests BIGINT NOT NULL DEFAULT 0,
total_tokens BIGINT NOT NULL DEFAULT 0,
total_cost_usd DOUBLE NOT NULL DEFAULT 0,
metadata TEXT,
expires_at BIGINT,
last_used_at BIGINT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY api_keys_key_hash_key (key_hash),
KEY api_keys_user_id_idx (user_id)
);
CREATE TABLE IF NOT EXISTS audit_logs (
id VARCHAR(64) PRIMARY KEY,
event_type VARCHAR(64) NOT NULL,
user_id VARCHAR(64),
api_key_id VARCHAR(64),
description TEXT NOT NULL,
ip_address VARCHAR(64),
user_agent VARCHAR(512),
request_id VARCHAR(128),
event_metadata TEXT,
status_code INT,
error_message TEXT,
created_at BIGINT NOT NULL,
KEY audit_logs_created_at_idx (created_at),
KEY audit_logs_event_type_idx (event_type),
KEY audit_logs_request_id_idx (request_id),
KEY audit_logs_user_id_idx (user_id)
);
CREATE TABLE IF NOT EXISTS announcements (
id VARCHAR(64) PRIMARY KEY,
title VARCHAR(200) NOT NULL,
content TEXT NOT NULL,
`type` VARCHAR(32) NOT NULL DEFAULT 'info',
priority INT NOT NULL DEFAULT 0,
author_id VARCHAR(64),
is_active TINYINT(1) NOT NULL DEFAULT 1,
is_pinned TINYINT(1) NOT NULL DEFAULT 0,
start_time BIGINT,
end_time BIGINT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY announcements_author_id_idx (author_id),
KEY announcements_created_at_idx (created_at),
KEY announcements_is_active_idx (is_active)
);
CREATE TABLE IF NOT EXISTS announcement_reads (
id VARCHAR(64) PRIMARY KEY,
user_id VARCHAR(64) NOT NULL,
announcement_id VARCHAR(64) NOT NULL,
read_at BIGINT NOT NULL,
UNIQUE KEY uq_user_announcement (user_id, announcement_id),
KEY announcement_reads_announcement_id_idx (announcement_id),
KEY announcement_reads_user_id_idx (user_id)
);
CREATE TABLE IF NOT EXISTS management_tokens (
id VARCHAR(64) PRIMARY KEY,
user_id VARCHAR(64) NOT NULL,
name VARCHAR(255) NOT NULL,
description TEXT,
token_hash VARCHAR(255) NOT NULL,
token_prefix VARCHAR(64),
allowed_ips TEXT,
expires_at BIGINT,
last_used_at BIGINT,
last_used_ip VARCHAR(255),
usage_count BIGINT NOT NULL DEFAULT 0,
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY management_tokens_token_hash_key (token_hash),
UNIQUE KEY uq_management_tokens_user_name (user_id, name),
KEY management_tokens_user_id_idx (user_id)
);
CREATE TABLE IF NOT EXISTS billing_rules (
id VARCHAR(64) PRIMARY KEY,
global_model_id VARCHAR(64),
model_id VARCHAR(64),
name VARCHAR(255) NOT NULL,
task_type VARCHAR(64) NOT NULL DEFAULT 'chat',
expression TEXT NOT NULL,
variables TEXT NOT NULL,
dimension_mappings TEXT NOT NULL,
is_enabled TINYINT(1) NOT NULL DEFAULT 1,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY billing_rules_global_model_task_idx (global_model_id, task_type, is_enabled),
KEY billing_rules_model_task_idx (model_id, task_type, is_enabled)
);
CREATE TABLE IF NOT EXISTS dimension_collectors (
id VARCHAR(64) PRIMARY KEY,
api_format VARCHAR(64) NOT NULL,
task_type VARCHAR(64) NOT NULL,
dimension_name VARCHAR(128) NOT NULL,
source_type VARCHAR(64) NOT NULL,
source_path VARCHAR(255),
value_type VARCHAR(64) NOT NULL DEFAULT 'float',
transform_expression TEXT,
default_value VARCHAR(255),
priority INT NOT NULL DEFAULT 0,
is_enabled TINYINT(1) NOT NULL DEFAULT 1,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY dimension_collectors_enabled_idx (
api_format,
task_type,
dimension_name,
priority,
is_enabled
)
);
CREATE TABLE IF NOT EXISTS providers (
id VARCHAR(64) PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT,
website VARCHAR(500),
provider_type VARCHAR(64) NOT NULL,
billing_type VARCHAR(64),
monthly_quota_usd DOUBLE,
monthly_used_usd DOUBLE,
quota_reset_day INT,
quota_last_reset_at BIGINT,
quota_expires_at BIGINT,
enabled TINYINT(1) NOT NULL DEFAULT 1,
is_active TINYINT(1) NOT NULL DEFAULT 1,
priority BIGINT NOT NULL DEFAULT 0,
provider_priority INT NOT NULL DEFAULT 100,
keep_priority_on_conversion TINYINT(1) NOT NULL DEFAULT 0,
enable_format_conversion TINYINT(1) NOT NULL DEFAULT 1,
concurrent_limit INT,
max_retries INT,
proxy TEXT,
request_timeout DOUBLE,
stream_first_byte_timeout DOUBLE,
config TEXT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY providers_name_key (name)
);
CREATE TABLE IF NOT EXISTS provider_api_keys (
id VARCHAR(64) PRIMARY KEY,
provider_id VARCHAR(64) NOT NULL,
name VARCHAR(255) NOT NULL,
api_key TEXT,
encrypted_key TEXT,
auth_type VARCHAR(32) NOT NULL DEFAULT 'api_key',
auth_config TEXT,
note TEXT,
internal_priority INT NOT NULL DEFAULT 50,
capabilities TEXT,
api_formats TEXT,
auth_type_by_format TEXT,
allow_auth_channel_mismatch_formats TEXT,
rate_multipliers TEXT,
global_priority_by_format TEXT,
allowed_models TEXT,
expires_at BIGINT,
cache_ttl_minutes INT NOT NULL DEFAULT 5,
max_probe_interval_minutes INT NOT NULL DEFAULT 32,
proxy TEXT,
fingerprint TEXT,
concurrent_limit INT,
learned_rpm_limit INT,
concurrent_429_count INT NOT NULL DEFAULT 0,
rpm_429_count INT NOT NULL DEFAULT 0,
last_429_at BIGINT,
last_429_type VARCHAR(64),
adjustment_history TEXT,
utilization_samples TEXT,
last_probe_increase_at BIGINT,
last_rpm_peak INT,
request_count BIGINT NOT NULL DEFAULT 0,
total_tokens BIGINT NOT NULL DEFAULT 0,
total_cost_usd DOUBLE NOT NULL DEFAULT 0,
success_count BIGINT NOT NULL DEFAULT 0,
error_count BIGINT NOT NULL DEFAULT 0,
total_response_time_ms BIGINT NOT NULL DEFAULT 0,
last_used_at BIGINT,
auto_fetch_models TINYINT(1) NOT NULL DEFAULT 0,
last_models_fetch_at BIGINT,
last_models_fetch_error TEXT,
locked_models TEXT,
model_include_patterns TEXT,
model_exclude_patterns TEXT,
upstream_metadata TEXT,
oauth_invalid_at BIGINT,
oauth_invalid_reason VARCHAR(255),
status_snapshot TEXT,
health_by_format TEXT,
circuit_breaker_by_format TEXT,
status VARCHAR(64) NOT NULL DEFAULT 'active',
is_active TINYINT(1) NOT NULL DEFAULT 1,
weight BIGINT NOT NULL DEFAULT 1,
rpm_limit BIGINT,
metadata TEXT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY provider_api_keys_provider_id_idx (provider_id)
);
CREATE TABLE IF NOT EXISTS gemini_file_mappings (
id VARCHAR(64) PRIMARY KEY,
file_name VARCHAR(512) NOT NULL,
key_id VARCHAR(64) NOT NULL,
user_id VARCHAR(64),
display_name VARCHAR(512),
mime_type VARCHAR(255),
source_hash VARCHAR(128),
created_at BIGINT NOT NULL,
expires_at BIGINT NOT NULL,
UNIQUE KEY gemini_file_mappings_file_name_key (file_name),
KEY gemini_file_mappings_key_id_idx (key_id),
KEY gemini_file_mappings_user_id_idx (user_id),
KEY gemini_file_mappings_expires_at_idx (expires_at),
KEY gemini_file_mappings_source_hash_idx (source_hash)
);
CREATE TABLE IF NOT EXISTS request_candidates (
id VARCHAR(64) PRIMARY KEY,
request_id VARCHAR(128) NOT NULL,
user_id VARCHAR(64),
api_key_id VARCHAR(64),
username VARCHAR(255),
api_key_name VARCHAR(255),
candidate_index INT NOT NULL,
retry_index INT NOT NULL DEFAULT 0,
provider_id VARCHAR(64),
endpoint_id VARCHAR(64),
key_id VARCHAR(64),
status VARCHAR(32) NOT NULL,
skip_reason TEXT,
is_cached TINYINT(1) NOT NULL DEFAULT 0,
status_code INT,
error_type VARCHAR(128),
error_message TEXT,
latency_ms INT,
concurrent_requests INT,
extra_data TEXT,
required_capabilities TEXT,
created_at BIGINT NOT NULL,
started_at BIGINT,
finished_at BIGINT,
UNIQUE KEY uq_request_candidate_with_retry (request_id, candidate_index, retry_index),
KEY request_candidates_request_id_idx (request_id),
KEY request_candidates_provider_id_idx (provider_id),
KEY request_candidates_endpoint_id_idx (endpoint_id),
KEY request_candidates_status_idx (status),
KEY request_candidates_created_at_idx (created_at),
KEY request_candidates_endpoint_status_created_idx (endpoint_id, status, created_at)
);
CREATE TABLE IF NOT EXISTS video_tasks (
id VARCHAR(64) PRIMARY KEY,
short_id VARCHAR(32),
request_id VARCHAR(128) NOT NULL,
user_id VARCHAR(64),
api_key_id VARCHAR(64),
username VARCHAR(255),
api_key_name VARCHAR(255),
external_task_id VARCHAR(255),
provider_id VARCHAR(64),
endpoint_id VARCHAR(64),
key_id VARCHAR(64),
client_api_format VARCHAR(128),
provider_api_format VARCHAR(128),
format_converted TINYINT(1) NOT NULL DEFAULT 0,
model VARCHAR(255),
prompt TEXT,
original_request_body TEXT,
duration_seconds INT,
resolution VARCHAR(64),
aspect_ratio VARCHAR(32),
size VARCHAR(64),
status VARCHAR(32) NOT NULL DEFAULT 'pending',
progress_percent INT NOT NULL DEFAULT 0,
progress_message TEXT,
retry_count INT NOT NULL DEFAULT 0,
poll_interval_seconds INT NOT NULL DEFAULT 10,
next_poll_at BIGINT,
poll_count INT NOT NULL DEFAULT 0,
max_poll_count INT NOT NULL DEFAULT 360,
created_at BIGINT NOT NULL,
submitted_at BIGINT,
completed_at BIGINT,
updated_at BIGINT NOT NULL,
error_code VARCHAR(128),
error_message TEXT,
video_url TEXT,
request_metadata TEXT,
UNIQUE KEY video_tasks_short_id_key (short_id),
UNIQUE KEY video_tasks_request_id_key (request_id),
KEY video_tasks_external_id_idx (external_task_id),
KEY video_tasks_next_poll_idx (next_poll_at),
KEY video_tasks_user_status_idx (user_id, status),
KEY video_tasks_api_key_id_idx (api_key_id),
KEY video_tasks_provider_id_idx (provider_id),
KEY video_tasks_endpoint_id_idx (endpoint_id),
KEY video_tasks_key_id_idx (key_id)
);
CREATE TABLE IF NOT EXISTS provider_endpoints (
id VARCHAR(64) PRIMARY KEY,
provider_id VARCHAR(64) NOT NULL,
name VARCHAR(255) NOT NULL,
base_url TEXT NOT NULL,
api_format VARCHAR(128),
api_family VARCHAR(128),
endpoint_kind VARCHAR(128),
enabled TINYINT(1) NOT NULL DEFAULT 1,
is_active TINYINT(1) NOT NULL DEFAULT 1,
health_score DOUBLE NOT NULL DEFAULT 1.0,
weight BIGINT NOT NULL DEFAULT 1,
header_rules TEXT,
body_rules TEXT,
max_retries INT,
custom_path TEXT,
metadata TEXT,
config TEXT,
format_acceptance_config TEXT,
proxy TEXT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY provider_endpoints_provider_id_idx (provider_id)
);
CREATE TABLE IF NOT EXISTS models (
id VARCHAR(64) PRIMARY KEY,
provider_id VARCHAR(64) NOT NULL,
global_model_id VARCHAR(64),
provider_model_name VARCHAR(255) NOT NULL,
global_model_name VARCHAR(255),
api_format VARCHAR(128),
enabled TINYINT(1) NOT NULL DEFAULT 1,
is_active TINYINT(1) NOT NULL DEFAULT 1,
is_available TINYINT(1) NOT NULL DEFAULT 1,
price_per_request DOUBLE,
tiered_pricing TEXT,
supports_vision TINYINT(1),
supports_function_calling TINYINT(1),
supports_streaming TINYINT(1),
supports_extended_thinking TINYINT(1),
supports_image_generation TINYINT(1),
provider_model_mappings TEXT,
config TEXT,
metadata TEXT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY models_provider_id_idx (provider_id)
);
CREATE TABLE IF NOT EXISTS global_models (
id VARCHAR(64) PRIMARY KEY,
name VARCHAR(255) NOT NULL,
display_name VARCHAR(255),
enabled TINYINT(1) NOT NULL DEFAULT 1,
is_active TINYINT(1) NOT NULL DEFAULT 1,
default_price_per_request DOUBLE,
default_tiered_pricing TEXT,
supported_capabilities TEXT,
usage_count BIGINT NOT NULL DEFAULT 0,
config TEXT,
metadata TEXT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY global_models_name_key (name)
);
CREATE TABLE IF NOT EXISTS system_configs (
id VARCHAR(64) PRIMARY KEY,
`key` VARCHAR(255) NOT NULL,
value TEXT NOT NULL,
description TEXT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY system_configs_key_key (`key`)
);
CREATE TABLE IF NOT EXISTS auth_modules (
id VARCHAR(64) PRIMARY KEY,
module_type VARCHAR(128) NOT NULL,
enabled TINYINT(1) NOT NULL DEFAULT 1,
config TEXT NOT NULL,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY auth_modules_module_type_key (module_type)
);
CREATE TABLE IF NOT EXISTS oauth_providers (
provider_type VARCHAR(64) PRIMARY KEY,
display_name VARCHAR(255) NOT NULL,
client_id TEXT NOT NULL,
client_secret_encrypted TEXT,
authorization_url_override VARCHAR(500),
token_url_override VARCHAR(500),
userinfo_url_override VARCHAR(500),
scopes TEXT,
redirect_uri VARCHAR(500) NOT NULL,
frontend_callback_url VARCHAR(500) NOT NULL,
attribute_mapping TEXT,
extra_config TEXT,
is_enabled TINYINT(1) NOT NULL DEFAULT 0,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL
);
CREATE TABLE IF NOT EXISTS ldap_configs (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
server_url VARCHAR(255) NOT NULL,
bind_dn TEXT NOT NULL,
bind_password_encrypted TEXT,
base_dn TEXT NOT NULL,
user_search_filter TEXT NOT NULL DEFAULT '(uid={username})',
username_attr VARCHAR(50) NOT NULL DEFAULT 'uid',
email_attr VARCHAR(50) NOT NULL DEFAULT 'mail',
display_name_attr VARCHAR(50) NOT NULL DEFAULT 'cn',
is_enabled TINYINT(1) NOT NULL DEFAULT 0,
is_exclusive TINYINT(1) NOT NULL DEFAULT 0,
use_starttls TINYINT(1) NOT NULL DEFAULT 0,
connect_timeout INT NOT NULL DEFAULT 10,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL
);
CREATE TABLE IF NOT EXISTS user_oauth_links (
id VARCHAR(64) PRIMARY KEY,
user_id VARCHAR(64) NOT NULL,
provider_type VARCHAR(64) NOT NULL,
provider_user_id VARCHAR(255) NOT NULL,
provider_username VARCHAR(255),
provider_email VARCHAR(255),
extra_data TEXT,
linked_at BIGINT NOT NULL,
last_login_at BIGINT,
KEY user_oauth_links_provider_type_idx (provider_type),
KEY user_oauth_links_user_id_idx (user_id)
);
CREATE TABLE IF NOT EXISTS proxy_nodes (
id VARCHAR(64) PRIMARY KEY,
name VARCHAR(255) NOT NULL,
ip VARCHAR(512) NOT NULL,
port INT NOT NULL,
region VARCHAR(100),
status VARCHAR(32) NOT NULL DEFAULT 'online',
registered_by VARCHAR(64),
last_heartbeat_at BIGINT,
heartbeat_interval INT NOT NULL DEFAULT 30,
active_connections INT NOT NULL DEFAULT 0,
total_requests BIGINT NOT NULL DEFAULT 0,
avg_latency_ms DOUBLE,
is_manual TINYINT(1) NOT NULL DEFAULT 0,
proxy_url VARCHAR(500),
proxy_username VARCHAR(255),
proxy_password VARCHAR(500),
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
remote_config TEXT,
config_version INT NOT NULL DEFAULT 0,
hardware_info TEXT,
estimated_max_concurrency INT,
tunnel_mode TINYINT(1) NOT NULL DEFAULT 0,
tunnel_connected TINYINT(1) NOT NULL DEFAULT 0,
tunnel_connected_at BIGINT,
failed_requests BIGINT NOT NULL DEFAULT 0,
dns_failures BIGINT NOT NULL DEFAULT 0,
stream_errors BIGINT NOT NULL DEFAULT 0,
proxy_metadata TEXT
);
CREATE TABLE IF NOT EXISTS proxy_node_events (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
node_id VARCHAR(64) NOT NULL,
event_type VARCHAR(64) NOT NULL,
detail VARCHAR(500),
created_at BIGINT NOT NULL
);
CREATE TABLE IF NOT EXISTS wallets (
id VARCHAR(64) PRIMARY KEY,
user_id VARCHAR(64),
api_key_id VARCHAR(64),
balance DOUBLE NOT NULL DEFAULT 0,
gift_balance DOUBLE NOT NULL DEFAULT 0,
limit_mode VARCHAR(64) NOT NULL DEFAULT 'finite',
currency VARCHAR(16) NOT NULL DEFAULT 'USD',
status VARCHAR(64) NOT NULL DEFAULT 'active',
total_recharged DOUBLE NOT NULL DEFAULT 0,
total_consumed DOUBLE NOT NULL DEFAULT 0,
total_refunded DOUBLE NOT NULL DEFAULT 0,
total_adjusted DOUBLE NOT NULL DEFAULT 0,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY wallets_user_id_key (user_id),
UNIQUE KEY wallets_api_key_id_key (api_key_id),
KEY wallets_api_key_id_idx (api_key_id),
KEY wallets_user_id_idx (user_id)
);
CREATE TABLE IF NOT EXISTS wallet_transactions (
id VARCHAR(64) PRIMARY KEY,
wallet_id VARCHAR(64) NOT NULL,
category VARCHAR(64) NOT NULL,
reason_code VARCHAR(64) NOT NULL,
amount DOUBLE NOT NULL,
balance_before DOUBLE NOT NULL,
balance_after DOUBLE NOT NULL,
recharge_balance_before DOUBLE NOT NULL,
recharge_balance_after DOUBLE NOT NULL,
gift_balance_before DOUBLE NOT NULL,
gift_balance_after DOUBLE NOT NULL,
link_type VARCHAR(64),
link_id VARCHAR(128),
operator_id VARCHAR(64),
description TEXT,
created_at BIGINT NOT NULL,
KEY idx_wallet_tx_wallet_created (wallet_id, created_at),
KEY idx_wallet_tx_category_created (category, created_at),
KEY idx_wallet_tx_reason_created (reason_code, created_at),
KEY idx_wallet_tx_link (link_type, link_id),
KEY ix_wallet_transactions_operator_id (operator_id)
);
CREATE TABLE IF NOT EXISTS wallet_daily_usage_ledgers (
id VARCHAR(64) PRIMARY KEY,
wallet_id VARCHAR(64) NOT NULL,
billing_date VARCHAR(16) NOT NULL,
billing_timezone VARCHAR(64) NOT NULL,
total_cost_usd DOUBLE NOT NULL DEFAULT 0,
total_requests BIGINT NOT NULL DEFAULT 0,
input_tokens BIGINT NOT NULL DEFAULT 0,
output_tokens BIGINT NOT NULL DEFAULT 0,
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
first_finalized_at BIGINT,
last_finalized_at BIGINT,
aggregated_at BIGINT NOT NULL,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY idx_wallet_daily_usage_wallet_date (wallet_id, billing_timezone, billing_date)
);
CREATE TABLE IF NOT EXISTS payment_orders (
id VARCHAR(64) PRIMARY KEY,
order_no VARCHAR(128) NOT NULL,
wallet_id VARCHAR(64) NOT NULL,
user_id VARCHAR(64),
amount_usd DOUBLE NOT NULL,
pay_amount DOUBLE,
pay_currency VARCHAR(16),
exchange_rate DOUBLE,
refunded_amount_usd DOUBLE NOT NULL DEFAULT 0,
refundable_amount_usd DOUBLE NOT NULL DEFAULT 0,
payment_method VARCHAR(64) NOT NULL,
gateway_order_id VARCHAR(128),
gateway_response TEXT,
status VARCHAR(64) NOT NULL DEFAULT 'pending',
created_at BIGINT NOT NULL,
paid_at BIGINT,
credited_at BIGINT,
expires_at BIGINT,
UNIQUE KEY uq_payment_orders_order_no (order_no),
KEY idx_payment_orders_wallet_created (wallet_id, created_at),
KEY idx_payment_orders_user_created (user_id, created_at),
KEY idx_payment_orders_status (status),
KEY idx_payment_orders_gateway_order_id (gateway_order_id)
);
CREATE TABLE IF NOT EXISTS payment_callbacks (
id VARCHAR(64) PRIMARY KEY,
payment_order_id VARCHAR(64),
payment_method VARCHAR(64) NOT NULL,
callback_key VARCHAR(128) NOT NULL,
order_no VARCHAR(128),
gateway_order_id VARCHAR(128),
payload_hash VARCHAR(128),
signature_valid TINYINT(1) NOT NULL DEFAULT 0,
status VARCHAR(64) NOT NULL DEFAULT 'received',
payload TEXT,
error_message TEXT,
created_at BIGINT NOT NULL,
processed_at BIGINT,
UNIQUE KEY uq_payment_callbacks_callback_key (callback_key),
KEY idx_payment_callbacks_order (order_no),
KEY idx_payment_callbacks_gateway_order (gateway_order_id),
KEY idx_payment_callbacks_created (created_at),
KEY ix_payment_callbacks_payment_order_id (payment_order_id)
);
CREATE TABLE IF NOT EXISTS refund_requests (
id VARCHAR(64) PRIMARY KEY,
refund_no VARCHAR(128) NOT NULL,
wallet_id VARCHAR(64) NOT NULL,
user_id VARCHAR(64),
payment_order_id VARCHAR(64),
source_type VARCHAR(64) NOT NULL,
source_id VARCHAR(128),
refund_mode VARCHAR(64) NOT NULL,
amount_usd DOUBLE NOT NULL,
status VARCHAR(64) NOT NULL DEFAULT 'pending_approval',
reason TEXT,
requested_by VARCHAR(64),
approved_by VARCHAR(64),
processed_by VARCHAR(64),
gateway_refund_id VARCHAR(128),
payout_method VARCHAR(64),
payout_reference VARCHAR(255),
payout_proof TEXT,
failure_reason TEXT,
idempotency_key VARCHAR(128),
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
processed_at BIGINT,
completed_at BIGINT,
UNIQUE KEY uq_refund_requests_refund_no (refund_no),
UNIQUE KEY uq_refund_requests_idempotency_key (idempotency_key),
KEY idx_refund_wallet_created (wallet_id, created_at),
KEY idx_refund_user_created (user_id, created_at),
KEY idx_refund_status (status),
KEY ix_refund_requests_payment_order_id (payment_order_id),
KEY ix_refund_requests_requested_by (requested_by),
KEY ix_refund_requests_approved_by (approved_by),
KEY ix_refund_requests_processed_by (processed_by)
);
CREATE TABLE IF NOT EXISTS redeem_code_batches (
id VARCHAR(64) PRIMARY KEY,
name VARCHAR(255) NOT NULL,
amount_usd DOUBLE NOT NULL,
currency VARCHAR(16) NOT NULL DEFAULT 'USD',
balance_bucket VARCHAR(64) NOT NULL DEFAULT 'gift',
total_count INT NOT NULL,
status VARCHAR(64) NOT NULL DEFAULT 'active',
description TEXT,
created_by VARCHAR(64),
expires_at BIGINT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY idx_redeem_code_batches_status (status, created_at)
);
CREATE TABLE IF NOT EXISTS redeem_codes (
id VARCHAR(64) PRIMARY KEY,
batch_id VARCHAR(64) NOT NULL,
code_hash VARCHAR(128) NOT NULL,
code_prefix VARCHAR(16) NOT NULL,
code_suffix VARCHAR(16) NOT NULL,
status VARCHAR(64) NOT NULL DEFAULT 'active',
redeemed_by_user_id VARCHAR(64),
redeemed_wallet_id VARCHAR(64),
redeemed_payment_order_id VARCHAR(64),
redeemed_at BIGINT,
disabled_by VARCHAR(64),
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY uq_redeem_codes_code_hash (code_hash),
KEY idx_redeem_codes_batch_created (batch_id, created_at),
KEY idx_redeem_codes_status (status, updated_at),
KEY idx_redeem_codes_redeemed_user (redeemed_by_user_id, redeemed_at),
KEY idx_redeem_codes_redeemed_order (redeemed_payment_order_id)
);
CREATE TABLE IF NOT EXISTS `usage` (
request_id VARCHAR(128) PRIMARY KEY,
id VARCHAR(128),
user_id VARCHAR(64),
api_key_id VARCHAR(64),
provider_name VARCHAR(255) NOT NULL DEFAULT 'unknown',
model VARCHAR(255) NOT NULL DEFAULT 'unknown',
target_model VARCHAR(255),
provider_id VARCHAR(64),
provider_endpoint_id VARCHAR(64),
provider_api_key_id VARCHAR(64),
request_type VARCHAR(64),
api_format VARCHAR(64),
api_family VARCHAR(64),
endpoint_kind VARCHAR(64),
endpoint_api_format VARCHAR(64),
provider_api_family VARCHAR(64),
provider_endpoint_kind VARCHAR(64),
has_format_conversion TINYINT(1) NOT NULL DEFAULT 0,
is_stream TINYINT(1) NOT NULL DEFAULT 0,
input_tokens BIGINT NOT NULL DEFAULT 0,
output_tokens BIGINT NOT NULL DEFAULT 0,
total_tokens BIGINT NOT NULL DEFAULT 0,
cache_creation_input_tokens BIGINT NOT NULL DEFAULT 0,
cache_creation_ephemeral_5m_input_tokens BIGINT NOT NULL DEFAULT 0,
cache_creation_ephemeral_1h_input_tokens BIGINT NOT NULL DEFAULT 0,
cache_read_input_tokens BIGINT NOT NULL DEFAULT 0,
cache_creation_cost_usd DOUBLE NOT NULL DEFAULT 0,
cache_read_cost_usd DOUBLE NOT NULL DEFAULT 0,
output_price_per_1m DOUBLE,
status_code INT,
error_message TEXT,
error_category VARCHAR(255),
response_time_ms BIGINT,
first_byte_time_ms BIGINT,
wallet_id VARCHAR(64),
status VARCHAR(64) NOT NULL DEFAULT 'completed',
billing_status VARCHAR(64) NOT NULL DEFAULT 'pending',
total_cost_usd DOUBLE NOT NULL DEFAULT 0,
actual_total_cost_usd DOUBLE NOT NULL DEFAULT 0,
request_metadata TEXT,
candidate_id VARCHAR(128),
candidate_index BIGINT,
key_name VARCHAR(255),
planner_kind VARCHAR(64),
route_family VARCHAR(128),
route_kind VARCHAR(128),
execution_path VARCHAR(128),
local_execution_runtime_miss_reason VARCHAR(255),
wallet_balance_before DOUBLE,
wallet_balance_after DOUBLE,
wallet_recharge_balance_before DOUBLE,
wallet_recharge_balance_after DOUBLE,
wallet_gift_balance_before DOUBLE,
wallet_gift_balance_after DOUBLE,
finalized_at BIGINT,
created_at_unix_ms BIGINT NOT NULL DEFAULT 0,
updated_at_unix_secs BIGINT NOT NULL DEFAULT 0,
KEY usage_api_key_id_idx (api_key_id),
KEY usage_billing_status_idx (billing_status),
KEY usage_created_at_idx (created_at_unix_ms),
KEY usage_provider_api_key_id_idx (provider_api_key_id),
KEY usage_provider_id_idx (provider_id),
KEY usage_request_id_idx (request_id),
KEY usage_user_id_idx (user_id),
KEY usage_wallet_id_idx (wallet_id)
);
CREATE TABLE IF NOT EXISTS usage_settlement_snapshots (
request_id VARCHAR(128) PRIMARY KEY,
billing_status VARCHAR(64) NOT NULL,
wallet_id VARCHAR(64),
wallet_balance_before DOUBLE,
wallet_balance_after DOUBLE,
wallet_recharge_balance_before DOUBLE,
wallet_recharge_balance_after DOUBLE,
wallet_gift_balance_before DOUBLE,
wallet_gift_balance_after DOUBLE,
provider_monthly_used_usd DOUBLE,
finalized_at BIGINT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY usage_settlement_snapshots_billing_status_idx (billing_status),
KEY usage_settlement_snapshots_wallet_id_idx (wallet_id)
);

View File

@@ -0,0 +1,18 @@
CREATE TABLE IF NOT EXISTS audit_logs (
id VARCHAR(64) PRIMARY KEY,
event_type VARCHAR(64) NOT NULL,
user_id VARCHAR(64),
api_key_id VARCHAR(64),
description TEXT NOT NULL,
ip_address VARCHAR(64),
user_agent VARCHAR(512),
request_id VARCHAR(128),
event_metadata TEXT,
status_code INT,
error_message TEXT,
created_at BIGINT NOT NULL,
KEY audit_logs_created_at_idx (created_at),
KEY audit_logs_event_type_idx (event_type),
KEY audit_logs_request_id_idx (request_id),
KEY audit_logs_user_id_idx (user_id)
);

View File

@@ -0,0 +1,44 @@
CREATE TABLE IF NOT EXISTS user_preferences (
id VARCHAR(36) PRIMARY KEY,
user_id VARCHAR(36) NOT NULL UNIQUE,
avatar_url VARCHAR(500),
bio TEXT,
default_provider_id VARCHAR(36),
theme VARCHAR(20) NOT NULL DEFAULT 'light',
language VARCHAR(10) NOT NULL DEFAULT 'zh-CN',
timezone VARCHAR(50) NOT NULL DEFAULT 'Asia/Shanghai',
email_notifications BOOLEAN NOT NULL DEFAULT TRUE,
usage_alerts BOOLEAN NOT NULL DEFAULT TRUE,
announcement_notifications BOOLEAN NOT NULL DEFAULT TRUE,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
INDEX user_preferences_default_provider_id_idx (default_provider_id),
INDEX user_preferences_user_id_idx (user_id)
);
CREATE TABLE IF NOT EXISTS user_sessions (
id VARCHAR(36) PRIMARY KEY,
user_id VARCHAR(36) NOT NULL,
client_device_id VARCHAR(128) NOT NULL,
device_label VARCHAR(120),
device_type VARCHAR(20) NOT NULL DEFAULT 'unknown',
browser_name VARCHAR(50),
browser_version VARCHAR(50),
os_name VARCHAR(50),
os_version VARCHAR(50),
device_model VARCHAR(100),
ip_address VARCHAR(45),
user_agent VARCHAR(1000),
client_hints TEXT,
refresh_token_hash VARCHAR(64) NOT NULL,
prev_refresh_token_hash VARCHAR(64),
rotated_at BIGINT,
last_seen_at BIGINT NOT NULL,
expires_at BIGINT NOT NULL,
revoked_at BIGINT,
revoke_reason VARCHAR(100),
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
INDEX user_sessions_user_active_idx (user_id, revoked_at, expires_at),
INDEX user_sessions_user_device_idx (user_id, client_device_id)
);

View File

@@ -0,0 +1,2 @@
ALTER TABLE users ADD COLUMN ldap_dn VARCHAR(1024);
ALTER TABLE users ADD COLUMN ldap_username VARCHAR(255);

View File

@@ -0,0 +1,3 @@
ALTER TABLE user_oauth_links
ADD UNIQUE KEY uq_user_oauth_links_provider_user (provider_type, provider_user_id),
ADD UNIQUE KEY uq_user_oauth_links_user_provider (user_id, provider_type);

View File

@@ -0,0 +1,177 @@
CREATE TABLE IF NOT EXISTS stats_hourly (
id VARCHAR(64) PRIMARY KEY,
hour_utc BIGINT NOT NULL,
total_requests BIGINT NOT NULL DEFAULT 0,
success_requests BIGINT NOT NULL DEFAULT 0,
error_requests BIGINT NOT NULL DEFAULT 0,
input_tokens BIGINT NOT NULL DEFAULT 0,
output_tokens BIGINT NOT NULL DEFAULT 0,
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
total_cost DOUBLE NOT NULL DEFAULT 0,
actual_total_cost DOUBLE NOT NULL DEFAULT 0,
avg_response_time_ms DOUBLE NOT NULL DEFAULT 0,
is_complete TINYINT(1) NOT NULL DEFAULT 0,
aggregated_at BIGINT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY uq_stats_hourly_hour (hour_utc)
);
CREATE TABLE IF NOT EXISTS stats_hourly_user (
id VARCHAR(64) PRIMARY KEY,
hour_utc BIGINT NOT NULL,
user_id VARCHAR(64) NOT NULL,
total_requests BIGINT NOT NULL DEFAULT 0,
success_requests BIGINT NOT NULL DEFAULT 0,
error_requests BIGINT NOT NULL DEFAULT 0,
input_tokens BIGINT NOT NULL DEFAULT 0,
output_tokens BIGINT NOT NULL DEFAULT 0,
total_cost DOUBLE NOT NULL DEFAULT 0,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY uq_stats_hourly_user (hour_utc, user_id)
);
CREATE TABLE IF NOT EXISTS stats_hourly_user_model (
id VARCHAR(64) PRIMARY KEY,
hour_utc BIGINT NOT NULL,
user_id VARCHAR(64) NOT NULL,
model VARCHAR(255) NOT NULL,
total_requests BIGINT NOT NULL DEFAULT 0,
input_tokens BIGINT NOT NULL DEFAULT 0,
output_tokens BIGINT NOT NULL DEFAULT 0,
total_cost DOUBLE NOT NULL DEFAULT 0,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY uq_stats_hourly_user_model (hour_utc, user_id, model)
);
CREATE TABLE IF NOT EXISTS stats_hourly_model (
id VARCHAR(64) PRIMARY KEY,
hour_utc BIGINT NOT NULL,
model VARCHAR(255) NOT NULL,
total_requests BIGINT NOT NULL DEFAULT 0,
input_tokens BIGINT NOT NULL DEFAULT 0,
output_tokens BIGINT NOT NULL DEFAULT 0,
total_cost DOUBLE NOT NULL DEFAULT 0,
avg_response_time_ms DOUBLE NOT NULL DEFAULT 0,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY uq_stats_hourly_model (hour_utc, model)
);
CREATE TABLE IF NOT EXISTS stats_hourly_provider (
id VARCHAR(64) PRIMARY KEY,
hour_utc BIGINT NOT NULL,
provider_name VARCHAR(255) NOT NULL,
total_requests BIGINT NOT NULL DEFAULT 0,
input_tokens BIGINT NOT NULL DEFAULT 0,
output_tokens BIGINT NOT NULL DEFAULT 0,
total_cost DOUBLE NOT NULL DEFAULT 0,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY uq_stats_hourly_provider (hour_utc, provider_name)
);
CREATE TABLE IF NOT EXISTS stats_daily (
id VARCHAR(64) PRIMARY KEY,
`date` BIGINT NOT NULL,
total_requests BIGINT NOT NULL DEFAULT 0,
success_requests BIGINT NOT NULL DEFAULT 0,
error_requests BIGINT NOT NULL DEFAULT 0,
input_tokens BIGINT NOT NULL DEFAULT 0,
output_tokens BIGINT NOT NULL DEFAULT 0,
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
total_cost DOUBLE NOT NULL DEFAULT 0,
actual_total_cost DOUBLE NOT NULL DEFAULT 0,
avg_response_time_ms DOUBLE NOT NULL DEFAULT 0,
fallback_count BIGINT NOT NULL DEFAULT 0,
unique_models BIGINT NOT NULL DEFAULT 0,
unique_providers BIGINT NOT NULL DEFAULT 0,
is_complete TINYINT(1) NOT NULL DEFAULT 0,
aggregated_at BIGINT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY uq_stats_daily_date (`date`)
);
CREATE TABLE IF NOT EXISTS stats_daily_model (
id VARCHAR(64) PRIMARY KEY,
`date` BIGINT NOT NULL,
model VARCHAR(255) NOT NULL,
total_requests BIGINT NOT NULL DEFAULT 0,
input_tokens BIGINT NOT NULL DEFAULT 0,
output_tokens BIGINT NOT NULL DEFAULT 0,
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
total_cost DOUBLE NOT NULL DEFAULT 0,
avg_response_time_ms DOUBLE NOT NULL DEFAULT 0,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY uq_stats_daily_model (`date`, model)
);
CREATE TABLE IF NOT EXISTS stats_daily_provider (
id VARCHAR(64) PRIMARY KEY,
`date` BIGINT NOT NULL,
provider_name VARCHAR(255) NOT NULL,
total_requests BIGINT NOT NULL DEFAULT 0,
input_tokens BIGINT NOT NULL DEFAULT 0,
output_tokens BIGINT NOT NULL DEFAULT 0,
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
total_cost DOUBLE NOT NULL DEFAULT 0,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY uq_stats_daily_provider (`date`, provider_name)
);
CREATE TABLE IF NOT EXISTS stats_daily_api_key (
id VARCHAR(64) PRIMARY KEY,
api_key_id VARCHAR(64) NOT NULL,
`date` BIGINT NOT NULL,
total_requests BIGINT NOT NULL DEFAULT 0,
success_requests BIGINT NOT NULL DEFAULT 0,
error_requests BIGINT NOT NULL DEFAULT 0,
input_tokens BIGINT NOT NULL DEFAULT 0,
output_tokens BIGINT NOT NULL DEFAULT 0,
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
total_cost DOUBLE NOT NULL DEFAULT 0,
api_key_name VARCHAR(255),
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY uq_stats_daily_api_key (`date`, api_key_id)
);
CREATE TABLE IF NOT EXISTS stats_daily_error (
id VARCHAR(64) PRIMARY KEY,
`date` BIGINT NOT NULL,
error_category VARCHAR(255) NOT NULL,
provider_name VARCHAR(255),
model VARCHAR(255),
count BIGINT NOT NULL DEFAULT 0,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY uq_stats_daily_error (`date`, error_category, provider_name, model)
);
CREATE TABLE IF NOT EXISTS stats_user_daily (
id VARCHAR(64) PRIMARY KEY,
user_id VARCHAR(64) NOT NULL,
`date` BIGINT NOT NULL,
total_requests BIGINT NOT NULL DEFAULT 0,
success_requests BIGINT NOT NULL DEFAULT 0,
error_requests BIGINT NOT NULL DEFAULT 0,
input_tokens BIGINT NOT NULL DEFAULT 0,
output_tokens BIGINT NOT NULL DEFAULT 0,
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
total_cost DOUBLE NOT NULL DEFAULT 0,
username VARCHAR(255),
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY uq_stats_user_daily (`date`, user_id)
);

View File

@@ -165,6 +165,8 @@ CREATE TABLE IF NOT EXISTS public.api_keys (
key_hash character varying(64) NOT NULL,
key_encrypted text,
name character varying(100),
key_prefix character varying(64),
status character varying(64) DEFAULT 'active'::character varying NOT NULL,
total_requests integer DEFAULT 0,
total_cost_usd numeric(20,8) DEFAULT '0'::double precision,
is_standalone boolean DEFAULT false NOT NULL,
@@ -178,6 +180,7 @@ CREATE TABLE IF NOT EXISTS public.api_keys (
last_used_at timestamp with time zone,
expires_at timestamp with time zone,
auto_delete_on_expiry boolean DEFAULT false NOT NULL,
metadata json,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
is_locked boolean DEFAULT false NOT NULL,
@@ -276,15 +279,17 @@ CREATE TABLE IF NOT EXISTS public.gemini_file_mappings (
CREATE TABLE IF NOT EXISTS public.global_models (
id character varying(36) NOT NULL,
name character varying(100) NOT NULL,
display_name character varying(100) NOT NULL,
display_name character varying(100),
enabled boolean DEFAULT true NOT NULL,
default_price_per_request numeric(20,8),
default_tiered_pricing json NOT NULL,
default_tiered_pricing json,
supported_capabilities json,
is_active boolean DEFAULT true NOT NULL,
usage_count integer DEFAULT 0 NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
config jsonb
config jsonb,
metadata json
);
@@ -366,8 +371,11 @@ CREATE TABLE IF NOT EXISTS public.management_tokens (
CREATE TABLE IF NOT EXISTS public.models (
id character varying(36) NOT NULL,
provider_id character varying(36) NOT NULL,
global_model_id character varying(36) NOT NULL,
global_model_id character varying(36),
provider_model_name character varying(200) NOT NULL,
global_model_name character varying(255),
api_format character varying(128),
enabled boolean DEFAULT true NOT NULL,
price_per_request numeric(20,8),
tiered_pricing json,
supports_vision boolean,
@@ -380,7 +388,8 @@ CREATE TABLE IF NOT EXISTS public.models (
config json,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
provider_model_mappings jsonb
provider_model_mappings jsonb,
metadata json
);
@@ -465,6 +474,7 @@ CREATE TABLE IF NOT EXISTS public.payment_orders (
CREATE TABLE IF NOT EXISTS public.provider_api_keys (
id character varying(36) NOT NULL,
api_key text,
encrypted_key text,
name character varying(100) NOT NULL,
note character varying(500),
internal_priority integer DEFAULT 50,
@@ -515,7 +525,10 @@ CREATE TABLE IF NOT EXISTS public.provider_api_keys (
fingerprint json,
total_tokens bigint NOT NULL,
total_cost_usd numeric(20,8) NOT NULL,
status_snapshot json
status_snapshot json,
status character varying(64) DEFAULT 'active'::character varying NOT NULL,
weight bigint DEFAULT 1 NOT NULL,
metadata json
);
@@ -527,10 +540,13 @@ CREATE TABLE IF NOT EXISTS public.provider_api_keys (
CREATE TABLE IF NOT EXISTS public.provider_endpoints (
id character varying(36) NOT NULL,
provider_id character varying(36) NOT NULL,
api_format character varying(50) NOT NULL,
name character varying(255),
api_format character varying(50),
base_url character varying(500) NOT NULL,
max_retries integer DEFAULT 3,
enabled boolean DEFAULT true NOT NULL,
is_active boolean DEFAULT true NOT NULL,
weight bigint DEFAULT 1 NOT NULL,
custom_path character varying(200),
config json,
created_at timestamp with time zone DEFAULT now() NOT NULL,
@@ -541,7 +557,8 @@ CREATE TABLE IF NOT EXISTS public.provider_endpoints (
api_family character varying(50),
endpoint_kind character varying(50),
body_rules json,
health_score double precision DEFAULT 1.0 NOT NULL
health_score double precision DEFAULT 1.0 NOT NULL,
metadata json
);
@@ -582,6 +599,8 @@ CREATE TABLE IF NOT EXISTS public.providers (
quota_reset_day integer DEFAULT 30,
quota_last_reset_at timestamp with time zone,
quota_expires_at timestamp with time zone,
enabled boolean DEFAULT true NOT NULL,
priority bigint DEFAULT 0 NOT NULL,
provider_priority integer DEFAULT 100,
is_active boolean DEFAULT true NOT NULL,
concurrent_limit integer,
@@ -1002,6 +1021,22 @@ CREATE TABLE IF NOT EXISTS public.system_configs (
);
--
-- Name: auth_modules; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE IF NOT EXISTS public.auth_modules (
id character varying(36) NOT NULL,
module_type character varying(128) NOT NULL,
enabled boolean DEFAULT true NOT NULL,
config json NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT auth_modules_pkey PRIMARY KEY (id),
CONSTRAINT auth_modules_module_type_key UNIQUE (module_type)
);
--
-- Name: usage; Type: TABLE; Schema: public; Owner: -
@@ -1075,6 +1110,8 @@ CREATE TABLE IF NOT EXISTS public.usage (
provider_endpoint_kind character varying(50),
cache_creation_input_tokens_5m integer DEFAULT 0 NOT NULL,
cache_creation_input_tokens_1h integer DEFAULT 0 NOT NULL,
cache_creation_ephemeral_5m_input_tokens integer DEFAULT 0 NOT NULL,
cache_creation_ephemeral_1h_input_tokens integer DEFAULT 0 NOT NULL,
wallet_id character varying(36),
wallet_balance_before numeric(20,8),
wallet_balance_after numeric(20,8),
@@ -1092,7 +1129,9 @@ CREATE TABLE IF NOT EXISTS public.usage (
actual_cache_creation_cost_usd_1h numeric(20,8) DEFAULT '0'::numeric NOT NULL,
actual_cache_cost_usd numeric(20,8) DEFAULT '0'::numeric NOT NULL,
cache_creation_price_per_1m_5m numeric(20,8),
cache_creation_price_per_1m_1h numeric(20,8)
cache_creation_price_per_1m_1h numeric(20,8),
created_at_unix_ms bigint DEFAULT 0 NOT NULL,
updated_at_unix_secs bigint DEFAULT 0 NOT NULL
);
@@ -1189,6 +1228,7 @@ CREATE TABLE IF NOT EXISTS public.user_sessions (
CREATE TABLE IF NOT EXISTS public.users (
id character varying(36) NOT NULL,
external_id character varying(255),
email character varying(255),
username character varying(100) NOT NULL,
password_hash character varying(255),
@@ -1206,7 +1246,8 @@ CREATE TABLE IF NOT EXISTS public.users (
ldap_dn character varying(512),
ldap_username character varying(255),
email_verified boolean NOT NULL,
rate_limit integer
rate_limit integer,
metadata json
);
@@ -4579,7 +4620,6 @@ EXCEPTION
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
-- Restore a normal lookup path before sqlx records this migration in the
-- same transaction. sqlx inserts into `_sqlx_migrations` unqualified.
SELECT pg_catalog.set_config('search_path', 'public', true);

View File

@@ -0,0 +1,61 @@
ALTER TABLE public.users
ADD COLUMN IF NOT EXISTS external_id character varying(255),
ADD COLUMN IF NOT EXISTS metadata json;
CREATE TABLE IF NOT EXISTS public.auth_modules (
id character varying(36) NOT NULL,
module_type character varying(128) NOT NULL,
enabled boolean DEFAULT true NOT NULL,
config json NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT auth_modules_pkey PRIMARY KEY (id),
CONSTRAINT auth_modules_module_type_key UNIQUE (module_type)
);
ALTER TABLE public.api_keys
ADD COLUMN IF NOT EXISTS key_prefix character varying(64),
ADD COLUMN IF NOT EXISTS status character varying(64) DEFAULT 'active'::character varying NOT NULL,
ADD COLUMN IF NOT EXISTS metadata json;
ALTER TABLE public.providers
ADD COLUMN IF NOT EXISTS enabled boolean DEFAULT true NOT NULL,
ADD COLUMN IF NOT EXISTS priority bigint DEFAULT 0 NOT NULL;
ALTER TABLE public.provider_api_keys
ADD COLUMN IF NOT EXISTS encrypted_key text,
ADD COLUMN IF NOT EXISTS status character varying(64) DEFAULT 'active'::character varying NOT NULL,
ADD COLUMN IF NOT EXISTS weight bigint DEFAULT 1 NOT NULL,
ADD COLUMN IF NOT EXISTS metadata json;
ALTER TABLE public.provider_endpoints
ADD COLUMN IF NOT EXISTS name character varying(255),
ADD COLUMN IF NOT EXISTS enabled boolean DEFAULT true NOT NULL,
ADD COLUMN IF NOT EXISTS weight bigint DEFAULT 1 NOT NULL,
ADD COLUMN IF NOT EXISTS metadata json;
ALTER TABLE public.provider_endpoints
ALTER COLUMN api_format DROP NOT NULL;
ALTER TABLE public.global_models
ADD COLUMN IF NOT EXISTS enabled boolean DEFAULT true NOT NULL,
ADD COLUMN IF NOT EXISTS metadata json;
ALTER TABLE public.global_models
ALTER COLUMN display_name DROP NOT NULL,
ALTER COLUMN default_tiered_pricing DROP NOT NULL;
ALTER TABLE public.models
ADD COLUMN IF NOT EXISTS global_model_name character varying(255),
ADD COLUMN IF NOT EXISTS api_format character varying(128),
ADD COLUMN IF NOT EXISTS enabled boolean DEFAULT true NOT NULL,
ADD COLUMN IF NOT EXISTS metadata json;
ALTER TABLE public.models
ALTER COLUMN global_model_id DROP NOT NULL;
ALTER TABLE public.usage
ADD COLUMN IF NOT EXISTS cache_creation_ephemeral_5m_input_tokens integer DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS cache_creation_ephemeral_1h_input_tokens integer DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS created_at_unix_ms bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS updated_at_unix_secs bigint DEFAULT 0 NOT NULL;

View File

@@ -0,0 +1,810 @@
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY,
external_id TEXT,
email TEXT UNIQUE,
username TEXT UNIQUE,
password_hash TEXT,
role TEXT,
auth_source TEXT NOT NULL DEFAULT 'local',
email_verified INTEGER NOT NULL DEFAULT 0,
is_active INTEGER NOT NULL DEFAULT 1,
is_deleted INTEGER NOT NULL DEFAULT 0,
allowed_models TEXT,
allowed_providers TEXT,
allowed_api_formats TEXT,
model_capability_settings TEXT,
rate_limit INTEGER,
metadata TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
last_login_at INTEGER
);
CREATE TABLE IF NOT EXISTS api_keys (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
key_hash TEXT NOT NULL UNIQUE,
key_encrypted TEXT,
name TEXT,
key_prefix TEXT,
status TEXT NOT NULL DEFAULT 'active',
allowed_models TEXT,
allowed_providers TEXT,
allowed_api_formats TEXT,
rate_limit INTEGER DEFAULT 100,
concurrent_limit INTEGER,
force_capabilities TEXT,
is_active INTEGER NOT NULL DEFAULT 1,
is_locked INTEGER NOT NULL DEFAULT 0,
is_standalone INTEGER NOT NULL DEFAULT 0,
auto_delete_on_expiry INTEGER NOT NULL DEFAULT 0,
total_requests INTEGER NOT NULL DEFAULT 0,
total_tokens INTEGER NOT NULL DEFAULT 0,
total_cost_usd REAL NOT NULL DEFAULT 0,
metadata TEXT,
expires_at INTEGER,
last_used_at INTEGER,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS api_keys_user_id_idx ON api_keys (user_id);
CREATE TABLE IF NOT EXISTS audit_logs (
id TEXT PRIMARY KEY,
event_type TEXT NOT NULL,
user_id TEXT,
api_key_id TEXT,
description TEXT NOT NULL,
ip_address TEXT,
user_agent TEXT,
request_id TEXT,
event_metadata TEXT,
status_code INTEGER,
error_message TEXT,
created_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS audit_logs_created_at_idx ON audit_logs (created_at);
CREATE INDEX IF NOT EXISTS audit_logs_event_type_idx ON audit_logs (event_type);
CREATE INDEX IF NOT EXISTS audit_logs_request_id_idx ON audit_logs (request_id);
CREATE INDEX IF NOT EXISTS audit_logs_user_id_idx ON audit_logs (user_id);
CREATE TABLE IF NOT EXISTS announcements (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
content TEXT NOT NULL,
type TEXT NOT NULL DEFAULT 'info',
priority INTEGER NOT NULL DEFAULT 0,
author_id TEXT,
is_active INTEGER NOT NULL DEFAULT 1,
is_pinned INTEGER NOT NULL DEFAULT 0,
start_time INTEGER,
end_time INTEGER,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS announcements_author_id_idx ON announcements (author_id);
CREATE INDEX IF NOT EXISTS announcements_created_at_idx ON announcements (created_at);
CREATE INDEX IF NOT EXISTS announcements_is_active_idx ON announcements (is_active);
CREATE TABLE IF NOT EXISTS announcement_reads (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
announcement_id TEXT NOT NULL,
read_at INTEGER NOT NULL,
UNIQUE (user_id, announcement_id)
);
CREATE INDEX IF NOT EXISTS announcement_reads_announcement_id_idx ON announcement_reads (announcement_id);
CREATE INDEX IF NOT EXISTS announcement_reads_user_id_idx ON announcement_reads (user_id);
CREATE TABLE IF NOT EXISTS management_tokens (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
name TEXT NOT NULL,
description TEXT,
token_hash TEXT NOT NULL UNIQUE,
token_prefix TEXT,
allowed_ips TEXT,
expires_at INTEGER,
last_used_at INTEGER,
last_used_ip TEXT,
usage_count INTEGER NOT NULL DEFAULT 0,
is_active INTEGER NOT NULL DEFAULT 1,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (user_id, name)
);
CREATE INDEX IF NOT EXISTS management_tokens_user_id_idx ON management_tokens (user_id);
CREATE TABLE IF NOT EXISTS billing_rules (
id TEXT PRIMARY KEY,
global_model_id TEXT,
model_id TEXT,
name TEXT NOT NULL,
task_type TEXT NOT NULL DEFAULT 'chat',
expression TEXT NOT NULL,
variables TEXT NOT NULL DEFAULT '{}',
dimension_mappings TEXT NOT NULL DEFAULT '{}',
is_enabled INTEGER NOT NULL DEFAULT 1,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
CHECK (
(global_model_id IS NOT NULL AND model_id IS NULL)
OR (global_model_id IS NULL AND model_id IS NOT NULL)
)
);
CREATE UNIQUE INDEX IF NOT EXISTS uq_billing_rules_global_model_task
ON billing_rules (global_model_id, task_type)
WHERE is_enabled = 1 AND global_model_id IS NOT NULL;
CREATE UNIQUE INDEX IF NOT EXISTS uq_billing_rules_model_task
ON billing_rules (model_id, task_type)
WHERE is_enabled = 1 AND model_id IS NOT NULL;
CREATE TABLE IF NOT EXISTS dimension_collectors (
id TEXT PRIMARY KEY,
api_format TEXT NOT NULL,
task_type TEXT NOT NULL,
dimension_name TEXT NOT NULL,
source_type TEXT NOT NULL,
source_path TEXT,
value_type TEXT NOT NULL DEFAULT 'float',
transform_expression TEXT,
default_value TEXT,
priority INTEGER NOT NULL DEFAULT 0,
is_enabled INTEGER NOT NULL DEFAULT 1,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
CHECK (
(source_type = 'computed' AND source_path IS NULL AND transform_expression IS NOT NULL)
OR (source_type <> 'computed' AND source_path IS NOT NULL)
)
);
CREATE UNIQUE INDEX IF NOT EXISTS uq_dimension_collectors_enabled
ON dimension_collectors (api_format, task_type, dimension_name, priority)
WHERE is_enabled = 1;
CREATE TABLE IF NOT EXISTS providers (
id TEXT PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
description TEXT,
website TEXT,
provider_type TEXT NOT NULL,
billing_type TEXT,
monthly_quota_usd REAL,
monthly_used_usd REAL,
quota_reset_day INTEGER,
quota_last_reset_at INTEGER,
quota_expires_at INTEGER,
enabled INTEGER NOT NULL DEFAULT 1,
is_active INTEGER NOT NULL DEFAULT 1,
priority INTEGER NOT NULL DEFAULT 0,
provider_priority INTEGER NOT NULL DEFAULT 100,
keep_priority_on_conversion INTEGER NOT NULL DEFAULT 0,
enable_format_conversion INTEGER NOT NULL DEFAULT 1,
concurrent_limit INTEGER,
max_retries INTEGER,
proxy TEXT,
request_timeout REAL,
stream_first_byte_timeout REAL,
config TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS provider_api_keys (
id TEXT PRIMARY KEY,
provider_id TEXT NOT NULL,
name TEXT NOT NULL,
api_key TEXT,
encrypted_key TEXT,
auth_type TEXT NOT NULL DEFAULT 'api_key',
auth_config TEXT,
note TEXT,
internal_priority INTEGER NOT NULL DEFAULT 50,
capabilities TEXT,
api_formats TEXT,
auth_type_by_format TEXT,
allow_auth_channel_mismatch_formats TEXT,
rate_multipliers TEXT,
global_priority_by_format TEXT,
allowed_models TEXT,
expires_at INTEGER,
cache_ttl_minutes INTEGER NOT NULL DEFAULT 5,
max_probe_interval_minutes INTEGER NOT NULL DEFAULT 32,
proxy TEXT,
fingerprint TEXT,
concurrent_limit INTEGER,
learned_rpm_limit INTEGER,
concurrent_429_count INTEGER NOT NULL DEFAULT 0,
rpm_429_count INTEGER NOT NULL DEFAULT 0,
last_429_at INTEGER,
last_429_type TEXT,
adjustment_history TEXT,
utilization_samples TEXT,
last_probe_increase_at INTEGER,
last_rpm_peak INTEGER,
request_count INTEGER NOT NULL DEFAULT 0,
total_tokens INTEGER NOT NULL DEFAULT 0,
total_cost_usd REAL NOT NULL DEFAULT 0,
success_count INTEGER NOT NULL DEFAULT 0,
error_count INTEGER NOT NULL DEFAULT 0,
total_response_time_ms INTEGER NOT NULL DEFAULT 0,
last_used_at INTEGER,
auto_fetch_models INTEGER NOT NULL DEFAULT 0,
last_models_fetch_at INTEGER,
last_models_fetch_error TEXT,
locked_models TEXT,
model_include_patterns TEXT,
model_exclude_patterns TEXT,
upstream_metadata TEXT,
oauth_invalid_at INTEGER,
oauth_invalid_reason TEXT,
status_snapshot TEXT,
health_by_format TEXT,
circuit_breaker_by_format TEXT,
status TEXT NOT NULL DEFAULT 'active',
is_active INTEGER NOT NULL DEFAULT 1,
weight INTEGER NOT NULL DEFAULT 1,
rpm_limit INTEGER,
metadata TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS provider_api_keys_provider_id_idx ON provider_api_keys (provider_id);
CREATE TABLE IF NOT EXISTS gemini_file_mappings (
id TEXT PRIMARY KEY,
file_name TEXT NOT NULL UNIQUE,
key_id TEXT NOT NULL,
user_id TEXT,
display_name TEXT,
mime_type TEXT,
source_hash TEXT,
created_at INTEGER NOT NULL,
expires_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS gemini_file_mappings_key_id_idx ON gemini_file_mappings (key_id);
CREATE INDEX IF NOT EXISTS gemini_file_mappings_user_id_idx ON gemini_file_mappings (user_id);
CREATE INDEX IF NOT EXISTS gemini_file_mappings_expires_at_idx ON gemini_file_mappings (expires_at);
CREATE INDEX IF NOT EXISTS gemini_file_mappings_source_hash_idx ON gemini_file_mappings (source_hash);
CREATE TABLE IF NOT EXISTS request_candidates (
id TEXT PRIMARY KEY,
request_id TEXT NOT NULL,
user_id TEXT,
api_key_id TEXT,
username TEXT,
api_key_name TEXT,
candidate_index INTEGER NOT NULL,
retry_index INTEGER NOT NULL DEFAULT 0,
provider_id TEXT,
endpoint_id TEXT,
key_id TEXT,
status TEXT NOT NULL,
skip_reason TEXT,
is_cached INTEGER NOT NULL DEFAULT 0,
status_code INTEGER,
error_type TEXT,
error_message TEXT,
latency_ms INTEGER,
concurrent_requests INTEGER,
extra_data TEXT,
required_capabilities TEXT,
created_at INTEGER NOT NULL,
started_at INTEGER,
finished_at INTEGER,
UNIQUE (request_id, candidate_index, retry_index)
);
CREATE INDEX IF NOT EXISTS request_candidates_request_id_idx ON request_candidates (request_id);
CREATE INDEX IF NOT EXISTS request_candidates_provider_id_idx ON request_candidates (provider_id);
CREATE INDEX IF NOT EXISTS request_candidates_endpoint_id_idx ON request_candidates (endpoint_id);
CREATE INDEX IF NOT EXISTS request_candidates_status_idx ON request_candidates (status);
CREATE INDEX IF NOT EXISTS request_candidates_created_at_idx ON request_candidates (created_at);
CREATE INDEX IF NOT EXISTS request_candidates_endpoint_status_created_idx ON request_candidates (endpoint_id, status, created_at);
CREATE TABLE IF NOT EXISTS video_tasks (
id TEXT PRIMARY KEY,
short_id TEXT UNIQUE,
request_id TEXT NOT NULL UNIQUE,
user_id TEXT,
api_key_id TEXT,
username TEXT,
api_key_name TEXT,
external_task_id TEXT,
provider_id TEXT,
endpoint_id TEXT,
key_id TEXT,
client_api_format TEXT,
provider_api_format TEXT,
format_converted INTEGER NOT NULL DEFAULT 0,
model TEXT,
prompt TEXT,
original_request_body TEXT,
duration_seconds INTEGER,
resolution TEXT,
aspect_ratio TEXT,
size TEXT,
status TEXT NOT NULL DEFAULT 'pending',
progress_percent INTEGER NOT NULL DEFAULT 0,
progress_message TEXT,
retry_count INTEGER NOT NULL DEFAULT 0,
poll_interval_seconds INTEGER NOT NULL DEFAULT 10,
next_poll_at INTEGER,
poll_count INTEGER NOT NULL DEFAULT 0,
max_poll_count INTEGER NOT NULL DEFAULT 360,
created_at INTEGER NOT NULL,
submitted_at INTEGER,
completed_at INTEGER,
updated_at INTEGER NOT NULL,
error_code TEXT,
error_message TEXT,
video_url TEXT,
request_metadata TEXT
);
CREATE INDEX IF NOT EXISTS video_tasks_external_id_idx ON video_tasks (external_task_id);
CREATE INDEX IF NOT EXISTS video_tasks_next_poll_idx ON video_tasks (next_poll_at);
CREATE INDEX IF NOT EXISTS video_tasks_request_id_idx ON video_tasks (request_id);
CREATE INDEX IF NOT EXISTS video_tasks_user_status_idx ON video_tasks (user_id, status);
CREATE INDEX IF NOT EXISTS video_tasks_api_key_id_idx ON video_tasks (api_key_id);
CREATE INDEX IF NOT EXISTS video_tasks_provider_id_idx ON video_tasks (provider_id);
CREATE INDEX IF NOT EXISTS video_tasks_endpoint_id_idx ON video_tasks (endpoint_id);
CREATE INDEX IF NOT EXISTS video_tasks_key_id_idx ON video_tasks (key_id);
CREATE TABLE IF NOT EXISTS provider_endpoints (
id TEXT PRIMARY KEY,
provider_id TEXT NOT NULL,
name TEXT NOT NULL,
base_url TEXT NOT NULL,
api_format TEXT,
api_family TEXT,
endpoint_kind TEXT,
enabled INTEGER NOT NULL DEFAULT 1,
is_active INTEGER NOT NULL DEFAULT 1,
health_score REAL NOT NULL DEFAULT 1.0,
weight INTEGER NOT NULL DEFAULT 1,
header_rules TEXT,
body_rules TEXT,
max_retries INTEGER,
custom_path TEXT,
metadata TEXT,
config TEXT,
format_acceptance_config TEXT,
proxy TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS provider_endpoints_provider_id_idx ON provider_endpoints (provider_id);
CREATE TABLE IF NOT EXISTS models (
id TEXT PRIMARY KEY,
provider_id TEXT NOT NULL,
global_model_id TEXT,
provider_model_name TEXT NOT NULL,
global_model_name TEXT,
api_format TEXT,
enabled INTEGER NOT NULL DEFAULT 1,
is_active INTEGER NOT NULL DEFAULT 1,
is_available INTEGER NOT NULL DEFAULT 1,
price_per_request REAL,
tiered_pricing TEXT,
supports_vision INTEGER,
supports_function_calling INTEGER,
supports_streaming INTEGER,
supports_extended_thinking INTEGER,
supports_image_generation INTEGER,
provider_model_mappings TEXT,
config TEXT,
metadata TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS models_provider_id_idx ON models (provider_id);
CREATE TABLE IF NOT EXISTS global_models (
id TEXT PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
display_name TEXT,
enabled INTEGER NOT NULL DEFAULT 1,
is_active INTEGER NOT NULL DEFAULT 1,
default_price_per_request REAL,
default_tiered_pricing TEXT,
supported_capabilities TEXT,
usage_count INTEGER NOT NULL DEFAULT 0,
config TEXT,
metadata TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS system_configs (
id TEXT PRIMARY KEY,
key TEXT NOT NULL UNIQUE,
value TEXT NOT NULL,
description TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS auth_modules (
id TEXT PRIMARY KEY,
module_type TEXT NOT NULL UNIQUE,
enabled INTEGER NOT NULL DEFAULT 1,
config TEXT NOT NULL,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS oauth_providers (
provider_type TEXT PRIMARY KEY,
display_name TEXT NOT NULL,
client_id TEXT NOT NULL,
client_secret_encrypted TEXT,
authorization_url_override TEXT,
token_url_override TEXT,
userinfo_url_override TEXT,
scopes TEXT,
redirect_uri TEXT NOT NULL,
frontend_callback_url TEXT NOT NULL,
attribute_mapping TEXT,
extra_config TEXT,
is_enabled INTEGER NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS ldap_configs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
server_url TEXT NOT NULL,
bind_dn TEXT NOT NULL,
bind_password_encrypted TEXT,
base_dn TEXT NOT NULL,
user_search_filter TEXT DEFAULT '(uid={username})' NOT NULL,
username_attr TEXT DEFAULT 'uid' NOT NULL,
email_attr TEXT DEFAULT 'mail' NOT NULL,
display_name_attr TEXT DEFAULT 'cn' NOT NULL,
is_enabled INTEGER NOT NULL DEFAULT 0,
is_exclusive INTEGER NOT NULL DEFAULT 0,
use_starttls INTEGER NOT NULL DEFAULT 0,
connect_timeout INTEGER NOT NULL DEFAULT 10,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS user_oauth_links (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
provider_type TEXT NOT NULL,
provider_user_id TEXT NOT NULL,
provider_username TEXT,
provider_email TEXT,
extra_data TEXT,
linked_at INTEGER NOT NULL,
last_login_at INTEGER
);
CREATE INDEX IF NOT EXISTS user_oauth_links_provider_type_idx ON user_oauth_links (provider_type);
CREATE INDEX IF NOT EXISTS user_oauth_links_user_id_idx ON user_oauth_links (user_id);
CREATE TABLE IF NOT EXISTS proxy_nodes (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
ip TEXT NOT NULL,
port INTEGER NOT NULL,
region TEXT,
status TEXT NOT NULL DEFAULT 'online',
registered_by TEXT,
last_heartbeat_at INTEGER,
heartbeat_interval INTEGER NOT NULL DEFAULT 30,
active_connections INTEGER NOT NULL DEFAULT 0,
total_requests INTEGER NOT NULL DEFAULT 0,
avg_latency_ms REAL,
is_manual INTEGER NOT NULL DEFAULT 0,
proxy_url TEXT,
proxy_username TEXT,
proxy_password TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
remote_config TEXT,
config_version INTEGER NOT NULL DEFAULT 0,
hardware_info TEXT,
estimated_max_concurrency INTEGER,
tunnel_mode INTEGER NOT NULL DEFAULT 0,
tunnel_connected INTEGER NOT NULL DEFAULT 0,
tunnel_connected_at INTEGER,
failed_requests INTEGER NOT NULL DEFAULT 0,
dns_failures INTEGER NOT NULL DEFAULT 0,
stream_errors INTEGER NOT NULL DEFAULT 0,
proxy_metadata TEXT
);
CREATE TABLE IF NOT EXISTS proxy_node_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
node_id TEXT NOT NULL,
event_type TEXT NOT NULL,
detail TEXT,
created_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS wallets (
id TEXT PRIMARY KEY,
user_id TEXT UNIQUE,
api_key_id TEXT UNIQUE,
balance REAL NOT NULL DEFAULT 0,
gift_balance REAL NOT NULL DEFAULT 0,
limit_mode TEXT NOT NULL DEFAULT 'finite',
currency TEXT NOT NULL DEFAULT 'USD',
status TEXT NOT NULL DEFAULT 'active',
total_recharged REAL NOT NULL DEFAULT 0,
total_consumed REAL NOT NULL DEFAULT 0,
total_refunded REAL NOT NULL DEFAULT 0,
total_adjusted REAL NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS wallets_api_key_id_idx ON wallets (api_key_id);
CREATE INDEX IF NOT EXISTS wallets_user_id_idx ON wallets (user_id);
CREATE TABLE IF NOT EXISTS wallet_transactions (
id TEXT PRIMARY KEY,
wallet_id TEXT NOT NULL,
category TEXT NOT NULL,
reason_code TEXT NOT NULL,
amount REAL NOT NULL,
balance_before REAL NOT NULL,
balance_after REAL NOT NULL,
recharge_balance_before REAL NOT NULL,
recharge_balance_after REAL NOT NULL,
gift_balance_before REAL NOT NULL,
gift_balance_after REAL NOT NULL,
link_type TEXT,
link_id TEXT,
operator_id TEXT,
description TEXT,
created_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_wallet_tx_wallet_created
ON wallet_transactions (wallet_id, created_at);
CREATE INDEX IF NOT EXISTS idx_wallet_tx_category_created
ON wallet_transactions (category, created_at);
CREATE INDEX IF NOT EXISTS idx_wallet_tx_reason_created
ON wallet_transactions (reason_code, created_at);
CREATE INDEX IF NOT EXISTS idx_wallet_tx_link
ON wallet_transactions (link_type, link_id);
CREATE INDEX IF NOT EXISTS ix_wallet_transactions_operator_id
ON wallet_transactions (operator_id);
CREATE TABLE IF NOT EXISTS wallet_daily_usage_ledgers (
id TEXT PRIMARY KEY,
wallet_id TEXT NOT NULL,
billing_date TEXT NOT NULL,
billing_timezone TEXT NOT NULL,
total_cost_usd REAL NOT NULL DEFAULT 0,
total_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
first_finalized_at INTEGER,
last_finalized_at INTEGER,
aggregated_at INTEGER NOT NULL,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_wallet_daily_usage_wallet_date
ON wallet_daily_usage_ledgers (wallet_id, billing_timezone, billing_date);
CREATE TABLE IF NOT EXISTS payment_orders (
id TEXT PRIMARY KEY,
order_no TEXT NOT NULL UNIQUE,
wallet_id TEXT NOT NULL,
user_id TEXT,
amount_usd REAL NOT NULL,
pay_amount REAL,
pay_currency TEXT,
exchange_rate REAL,
refunded_amount_usd REAL NOT NULL DEFAULT 0,
refundable_amount_usd REAL NOT NULL DEFAULT 0,
payment_method TEXT NOT NULL,
gateway_order_id TEXT,
gateway_response TEXT,
status TEXT NOT NULL DEFAULT 'pending',
created_at INTEGER NOT NULL,
paid_at INTEGER,
credited_at INTEGER,
expires_at INTEGER
);
CREATE INDEX IF NOT EXISTS idx_payment_orders_wallet_created
ON payment_orders (wallet_id, created_at);
CREATE INDEX IF NOT EXISTS idx_payment_orders_user_created
ON payment_orders (user_id, created_at);
CREATE INDEX IF NOT EXISTS idx_payment_orders_status
ON payment_orders (status);
CREATE INDEX IF NOT EXISTS idx_payment_orders_gateway_order_id
ON payment_orders (gateway_order_id);
CREATE TABLE IF NOT EXISTS payment_callbacks (
id TEXT PRIMARY KEY,
payment_order_id TEXT,
payment_method TEXT NOT NULL,
callback_key TEXT NOT NULL UNIQUE,
order_no TEXT,
gateway_order_id TEXT,
payload_hash TEXT,
signature_valid INTEGER NOT NULL DEFAULT 0,
status TEXT NOT NULL DEFAULT 'received',
payload TEXT,
error_message TEXT,
created_at INTEGER NOT NULL,
processed_at INTEGER
);
CREATE INDEX IF NOT EXISTS idx_payment_callbacks_order
ON payment_callbacks (order_no);
CREATE INDEX IF NOT EXISTS idx_payment_callbacks_gateway_order
ON payment_callbacks (gateway_order_id);
CREATE INDEX IF NOT EXISTS idx_payment_callbacks_created
ON payment_callbacks (created_at);
CREATE INDEX IF NOT EXISTS ix_payment_callbacks_payment_order_id
ON payment_callbacks (payment_order_id);
CREATE TABLE IF NOT EXISTS refund_requests (
id TEXT PRIMARY KEY,
refund_no TEXT NOT NULL UNIQUE,
wallet_id TEXT NOT NULL,
user_id TEXT,
payment_order_id TEXT,
source_type TEXT NOT NULL,
source_id TEXT,
refund_mode TEXT NOT NULL,
amount_usd REAL NOT NULL,
status TEXT NOT NULL DEFAULT 'pending_approval',
reason TEXT,
requested_by TEXT,
approved_by TEXT,
processed_by TEXT,
gateway_refund_id TEXT,
payout_method TEXT,
payout_reference TEXT,
payout_proof TEXT,
failure_reason TEXT,
idempotency_key TEXT UNIQUE,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
processed_at INTEGER,
completed_at INTEGER
);
CREATE INDEX IF NOT EXISTS idx_refund_wallet_created
ON refund_requests (wallet_id, created_at);
CREATE INDEX IF NOT EXISTS idx_refund_user_created
ON refund_requests (user_id, created_at);
CREATE INDEX IF NOT EXISTS idx_refund_status
ON refund_requests (status);
CREATE INDEX IF NOT EXISTS ix_refund_requests_payment_order_id
ON refund_requests (payment_order_id);
CREATE INDEX IF NOT EXISTS ix_refund_requests_requested_by
ON refund_requests (requested_by);
CREATE INDEX IF NOT EXISTS ix_refund_requests_approved_by
ON refund_requests (approved_by);
CREATE INDEX IF NOT EXISTS ix_refund_requests_processed_by
ON refund_requests (processed_by);
CREATE TABLE IF NOT EXISTS redeem_code_batches (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
amount_usd REAL NOT NULL,
currency TEXT NOT NULL DEFAULT 'USD',
balance_bucket TEXT NOT NULL DEFAULT 'gift',
total_count INTEGER NOT NULL,
status TEXT NOT NULL DEFAULT 'active',
description TEXT,
created_by TEXT,
expires_at INTEGER,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_redeem_code_batches_status
ON redeem_code_batches (status, created_at);
CREATE TABLE IF NOT EXISTS redeem_codes (
id TEXT PRIMARY KEY,
batch_id TEXT NOT NULL,
code_hash TEXT NOT NULL UNIQUE,
code_prefix TEXT NOT NULL,
code_suffix TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'active',
redeemed_by_user_id TEXT,
redeemed_wallet_id TEXT,
redeemed_payment_order_id TEXT,
redeemed_at INTEGER,
disabled_by TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_batch_created
ON redeem_codes (batch_id, created_at);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_status
ON redeem_codes (status, updated_at);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_redeemed_user
ON redeem_codes (redeemed_by_user_id, redeemed_at);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_redeemed_order
ON redeem_codes (redeemed_payment_order_id);
CREATE TABLE IF NOT EXISTS "usage" (
request_id TEXT PRIMARY KEY,
id TEXT,
user_id TEXT,
api_key_id TEXT,
provider_name TEXT NOT NULL DEFAULT 'unknown',
model TEXT NOT NULL DEFAULT 'unknown',
target_model TEXT,
provider_id TEXT,
provider_endpoint_id TEXT,
provider_api_key_id TEXT,
request_type TEXT,
api_format TEXT,
api_family TEXT,
endpoint_kind TEXT,
endpoint_api_format TEXT,
provider_api_family TEXT,
provider_endpoint_kind TEXT,
has_format_conversion INTEGER NOT NULL DEFAULT 0,
is_stream INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
total_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_input_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_ephemeral_5m_input_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_ephemeral_1h_input_tokens INTEGER NOT NULL DEFAULT 0,
cache_read_input_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_cost_usd REAL NOT NULL DEFAULT 0,
cache_read_cost_usd REAL NOT NULL DEFAULT 0,
output_price_per_1m REAL,
status_code INTEGER,
error_message TEXT,
error_category TEXT,
response_time_ms INTEGER,
first_byte_time_ms INTEGER,
wallet_id TEXT,
status TEXT NOT NULL DEFAULT 'completed',
billing_status TEXT NOT NULL DEFAULT 'pending',
total_cost_usd REAL NOT NULL DEFAULT 0,
actual_total_cost_usd REAL NOT NULL DEFAULT 0,
request_metadata TEXT,
candidate_id TEXT,
candidate_index INTEGER,
key_name TEXT,
planner_kind TEXT,
route_family TEXT,
route_kind TEXT,
execution_path TEXT,
local_execution_runtime_miss_reason TEXT,
wallet_balance_before REAL,
wallet_balance_after REAL,
wallet_recharge_balance_before REAL,
wallet_recharge_balance_after REAL,
wallet_gift_balance_before REAL,
wallet_gift_balance_after REAL,
finalized_at INTEGER,
created_at_unix_ms INTEGER NOT NULL DEFAULT 0,
updated_at_unix_secs INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX IF NOT EXISTS usage_api_key_id_idx ON "usage" (api_key_id);
CREATE INDEX IF NOT EXISTS usage_billing_status_idx ON "usage" (billing_status);
CREATE INDEX IF NOT EXISTS usage_created_at_idx ON "usage" (created_at_unix_ms);
CREATE INDEX IF NOT EXISTS usage_provider_api_key_id_idx ON "usage" (provider_api_key_id);
CREATE INDEX IF NOT EXISTS usage_provider_id_idx ON "usage" (provider_id);
CREATE INDEX IF NOT EXISTS usage_request_id_idx ON "usage" (request_id);
CREATE INDEX IF NOT EXISTS usage_user_id_idx ON "usage" (user_id);
CREATE INDEX IF NOT EXISTS usage_wallet_id_idx ON "usage" (wallet_id);
CREATE TABLE IF NOT EXISTS usage_settlement_snapshots (
request_id TEXT PRIMARY KEY,
billing_status TEXT NOT NULL,
wallet_id TEXT,
wallet_balance_before REAL,
wallet_balance_after REAL,
wallet_recharge_balance_before REAL,
wallet_recharge_balance_after REAL,
wallet_gift_balance_before REAL,
wallet_gift_balance_after REAL,
provider_monthly_used_usd REAL,
finalized_at INTEGER,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS usage_settlement_snapshots_billing_status_idx
ON usage_settlement_snapshots (billing_status);
CREATE INDEX IF NOT EXISTS usage_settlement_snapshots_wallet_id_idx
ON usage_settlement_snapshots (wallet_id);

View File

@@ -0,0 +1,18 @@
CREATE TABLE IF NOT EXISTS audit_logs (
id TEXT PRIMARY KEY,
event_type TEXT NOT NULL,
user_id TEXT,
api_key_id TEXT,
description TEXT NOT NULL,
ip_address TEXT,
user_agent TEXT,
request_id TEXT,
event_metadata TEXT,
status_code INTEGER,
error_message TEXT,
created_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS audit_logs_created_at_idx ON audit_logs (created_at);
CREATE INDEX IF NOT EXISTS audit_logs_event_type_idx ON audit_logs (event_type);
CREATE INDEX IF NOT EXISTS audit_logs_request_id_idx ON audit_logs (request_id);
CREATE INDEX IF NOT EXISTS audit_logs_user_id_idx ON audit_logs (user_id);

View File

@@ -0,0 +1,48 @@
CREATE TABLE IF NOT EXISTS user_preferences (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL UNIQUE,
avatar_url TEXT,
bio TEXT,
default_provider_id TEXT,
theme TEXT NOT NULL DEFAULT 'light',
language TEXT NOT NULL DEFAULT 'zh-CN',
timezone TEXT NOT NULL DEFAULT 'Asia/Shanghai',
email_notifications INTEGER NOT NULL DEFAULT 1,
usage_alerts INTEGER NOT NULL DEFAULT 1,
announcement_notifications INTEGER NOT NULL DEFAULT 1,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS user_preferences_default_provider_id_idx
ON user_preferences (default_provider_id);
CREATE INDEX IF NOT EXISTS user_preferences_user_id_idx
ON user_preferences (user_id);
CREATE TABLE IF NOT EXISTS user_sessions (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
client_device_id TEXT NOT NULL,
device_label TEXT,
device_type TEXT NOT NULL DEFAULT 'unknown',
browser_name TEXT,
browser_version TEXT,
os_name TEXT,
os_version TEXT,
device_model TEXT,
ip_address TEXT,
user_agent TEXT,
client_hints TEXT,
refresh_token_hash TEXT NOT NULL,
prev_refresh_token_hash TEXT,
rotated_at INTEGER,
last_seen_at INTEGER NOT NULL,
expires_at INTEGER NOT NULL,
revoked_at INTEGER,
revoke_reason TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS user_sessions_user_active_idx
ON user_sessions (user_id, revoked_at, expires_at);
CREATE INDEX IF NOT EXISTS user_sessions_user_device_idx
ON user_sessions (user_id, client_device_id);

View File

@@ -0,0 +1,2 @@
ALTER TABLE users ADD COLUMN ldap_dn TEXT;
ALTER TABLE users ADD COLUMN ldap_username TEXT;

View File

@@ -0,0 +1,5 @@
CREATE UNIQUE INDEX IF NOT EXISTS uq_user_oauth_links_provider_user
ON user_oauth_links (provider_type, provider_user_id);
CREATE UNIQUE INDEX IF NOT EXISTS uq_user_oauth_links_user_provider
ON user_oauth_links (user_id, provider_type);

View File

@@ -0,0 +1,175 @@
CREATE TABLE IF NOT EXISTS stats_hourly (
id TEXT PRIMARY KEY,
hour_utc INTEGER NOT NULL UNIQUE,
total_requests INTEGER NOT NULL DEFAULT 0,
success_requests INTEGER NOT NULL DEFAULT 0,
error_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
actual_total_cost REAL NOT NULL DEFAULT 0,
avg_response_time_ms REAL NOT NULL DEFAULT 0,
is_complete INTEGER NOT NULL DEFAULT 0,
aggregated_at INTEGER,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS stats_hourly_user (
id TEXT PRIMARY KEY,
hour_utc INTEGER NOT NULL,
user_id TEXT NOT NULL,
total_requests INTEGER NOT NULL DEFAULT 0,
success_requests INTEGER NOT NULL DEFAULT 0,
error_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (hour_utc, user_id)
);
CREATE TABLE IF NOT EXISTS stats_hourly_user_model (
id TEXT PRIMARY KEY,
hour_utc INTEGER NOT NULL,
user_id TEXT NOT NULL,
model TEXT NOT NULL,
total_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (hour_utc, user_id, model)
);
CREATE TABLE IF NOT EXISTS stats_hourly_model (
id TEXT PRIMARY KEY,
hour_utc INTEGER NOT NULL,
model TEXT NOT NULL,
total_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
avg_response_time_ms REAL NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (hour_utc, model)
);
CREATE TABLE IF NOT EXISTS stats_hourly_provider (
id TEXT PRIMARY KEY,
hour_utc INTEGER NOT NULL,
provider_name TEXT NOT NULL,
total_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (hour_utc, provider_name)
);
CREATE TABLE IF NOT EXISTS stats_daily (
id TEXT PRIMARY KEY,
"date" INTEGER NOT NULL UNIQUE,
total_requests INTEGER NOT NULL DEFAULT 0,
success_requests INTEGER NOT NULL DEFAULT 0,
error_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
actual_total_cost REAL NOT NULL DEFAULT 0,
avg_response_time_ms REAL NOT NULL DEFAULT 0,
fallback_count INTEGER NOT NULL DEFAULT 0,
unique_models INTEGER NOT NULL DEFAULT 0,
unique_providers INTEGER NOT NULL DEFAULT 0,
is_complete INTEGER NOT NULL DEFAULT 0,
aggregated_at INTEGER,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS stats_daily_model (
id TEXT PRIMARY KEY,
"date" INTEGER NOT NULL,
model TEXT NOT NULL,
total_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
avg_response_time_ms REAL NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE ("date", model)
);
CREATE TABLE IF NOT EXISTS stats_daily_provider (
id TEXT PRIMARY KEY,
"date" INTEGER NOT NULL,
provider_name TEXT NOT NULL,
total_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE ("date", provider_name)
);
CREATE TABLE IF NOT EXISTS stats_daily_api_key (
id TEXT PRIMARY KEY,
api_key_id TEXT NOT NULL,
"date" INTEGER NOT NULL,
total_requests INTEGER NOT NULL DEFAULT 0,
success_requests INTEGER NOT NULL DEFAULT 0,
error_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
api_key_name TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE ("date", api_key_id)
);
CREATE TABLE IF NOT EXISTS stats_daily_error (
id TEXT PRIMARY KEY,
"date" INTEGER NOT NULL,
error_category TEXT NOT NULL,
provider_name TEXT,
model TEXT,
count INTEGER NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE ("date", error_category, provider_name, model)
);
CREATE TABLE IF NOT EXISTS stats_user_daily (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
"date" INTEGER NOT NULL,
total_requests INTEGER NOT NULL DEFAULT 0,
success_requests INTEGER NOT NULL DEFAULT 0,
error_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
username TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE ("date", user_id)
);

View File

@@ -0,0 +1,119 @@
# Aether Schema Source
This directory is the schema maintenance workspace. The executable migrations
remain in `../migrations/{postgres,mysql,sqlite}` because runtime code and
existing deployments still reference those paths. The Postgres bootstrap
snapshot is compiled from the source fragments here during `aether-data`
builds, so there is no checked-in bootstrap artifact.
The maintenance flow is:
```bash
bash crates/aether-data/schema/compose_schema.sh generate
bash crates/aether-data/schema/compose_schema.sh compose
bash crates/aether-data/schema/compose_schema.sh check
```
- `generate` renders `logical/*.toml` through `aether-data-schema` into
`generated/{postgres,mysql,sqlite}`. This is a build output, not another SQL
source to maintain.
- `compose` rewrites the executable SQL from the manifest order.
- `check` verifies generated output is current, confirms the bootstrap source
fragments still compose cleanly, and diffs each executable migration manifest
against the checked-in SQL.
- `split` regenerates fragments from the executable SQL and is mostly for
rebaselining after a deliberate bulk rewrite.
## What To Edit
The schema workspace has three normal source areas:
| Path | Role | Edit policy |
|---|---|---|
| `logical/*.toml` | Long-term logical table model shared by all SQL drivers. | Edit first for portable table-shape changes. |
| `drivers/{postgres,mysql,sqlite}/` | Current maintenance fragments for executable SQL. | Edit only for deployment compatibility, ordering, or generator gaps. |
| `bootstrap/postgres/` | Source fragments for the Postgres empty-database bootstrap snapshot. | Edit here when the bootstrap snapshot changes, then rebuild `aether-data` so `build.rs` regenerates the embedded snapshot. |
Everything else is output:
| Path | Role | Edit policy |
|---|---|---|
| `generated/{postgres,mysql,sqlite}/` | Machine-written SQL emitted from `logical/*.toml` for audit and drift detection. | Do not edit; regenerate with `compose_schema.sh generate`. |
| `../migrations/` | Runtime SQL artifacts embedded or executed by the application. | Regenerate through `compose_schema.sh compose`; do not edit independently. |
`generated/**` is deliberately checked in so reviews and CI can see exactly
what the logical schema compiler emits for each driver. It is not a fourth SQL
source of truth, and runtime code never loads migrations from it.
`overrides/` is an exception bucket, not a regular source tree. Keep it empty
except for its README until a real driver-specific SQL file is needed and added
to a manifest.
The generator can also be called directly:
```bash
cargo run -p aether-data-schema --bin aether-schema -- check
cargo run -p aether-data-schema --bin aether-schema -- generate
cargo run -p aether-data-schema --bin aether-schema -- print --driver postgres
```
## Logical Schema
`logical/*.toml` is the long-term source for table definitions. It covers the
clean baseline table set and the portable MySQL/SQLite table-creation
migrations. The generator emits driver-specific SQL under `generated/`; those
files include a directory README plus `Do not edit` headers and should only
change through `compose_schema.sh generate`.
`compose_schema.sh check` enforces two things:
- generated SQL must match the current logical TOML source
- bootstrap source fragments must still compose cleanly for the runtime build
- required executable SQL tables must have logical definitions, so new portable
tables cannot bypass the single-maintenance-source path
The migration path is incremental:
1. Add a table/domain to `logical/*.toml`.
2. Run `compose_schema.sh generate`.
3. Compare generated SQL to the current driver fragments.
4. Promote generated output into driver fragments only when that domain is
intentionally ready to stop being handwritten.
5. Keep driver-specific special cases in explicit override fragments under
`overrides/` only when they cannot live cleanly in a driver fragment.
6. Once a domain matches, move its baseline maintenance to generated output.
The existing `drivers/postgres`, `drivers/mysql`, and `drivers/sqlite`
fragment trees remain authoritative for executable migrations until a generated
fragment is deliberately promoted.
`overrides/` is reserved for rare driver-specific SQL that cannot be represented
by logical schema or the normal driver fragments. Keep it small and explicit.
## Targets
| Target | Executable SQL | Source manifest |
|---|---|---|
| Postgres baseline | `migrations/postgres/20260403000000_baseline.sql` | `drivers/postgres/baseline/manifest.txt` |
| Postgres empty-database snapshot | `aether-data` build output (`OUT_DIR/empty_database_snapshot.sql`) | `bootstrap/postgres/manifest.txt` |
| MySQL baseline | `migrations/mysql/20260403000000_baseline.sql` | `drivers/mysql/baseline/manifest.txt` |
| SQLite baseline | `migrations/sqlite/20260403000000_baseline.sql` | `drivers/sqlite/baseline/manifest.txt` |
Driver baseline source manifests are kept as a small set of numbered SQL
fragments. Postgres uses execution-phase fragments so the pg_dump ordering
remains byte-for-byte stable when composed:
- `001_types_and_tables.sql`
- `002_defaults.sql`
- `003_constraints.sql`
- `004_indexes.sql`
- `005_foreign_keys.sql`
- `006_footer.sql`
- `100_*` extension files for empty-database snapshot-only additions
MySQL and SQLite use similarly numbered domain fragments (`001_identity.sql`
through `006_usage.sql`) because their baselines are shorter and already
organized by domain.
The Rust migration tests compose these manifests too, so fragment drift is
caught during `cargo test -p aether-data split_baseline_sources_match_executable_migrations`.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
-- Name: ldap_configs id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.ldap_configs ALTER COLUMN id SET DEFAULT nextval('public.ldap_configs_id_seq'::regclass);
--
-- Name: proxy_node_events id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.proxy_node_events ALTER COLUMN id SET DEFAULT nextval('public.proxy_node_events_id_seq'::regclass);
--

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,851 @@
-- Name: announcement_reads announcement_reads_announcement_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.announcement_reads
ADD CONSTRAINT announcement_reads_announcement_id_fkey FOREIGN KEY (announcement_id) REFERENCES public.announcements(id);
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: announcement_reads announcement_reads_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.announcement_reads
ADD CONSTRAINT announcement_reads_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: announcements announcements_author_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.announcements
ADD CONSTRAINT announcements_author_id_fkey FOREIGN KEY (author_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: api_key_provider_mappings api_key_provider_mappings_api_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.api_key_provider_mappings
ADD CONSTRAINT api_key_provider_mappings_api_key_id_fkey FOREIGN KEY (api_key_id) REFERENCES public.api_keys(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: api_key_provider_mappings api_key_provider_mappings_provider_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.api_key_provider_mappings
ADD CONSTRAINT api_key_provider_mappings_provider_id_fkey FOREIGN KEY (provider_id) REFERENCES public.providers(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: api_keys api_keys_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.api_keys
ADD CONSTRAINT api_keys_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: audit_logs audit_logs_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.audit_logs
ADD CONSTRAINT audit_logs_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: billing_rules billing_rules_global_model_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.billing_rules
ADD CONSTRAINT billing_rules_global_model_id_fkey FOREIGN KEY (global_model_id) REFERENCES public.global_models(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: billing_rules billing_rules_model_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.billing_rules
ADD CONSTRAINT billing_rules_model_id_fkey FOREIGN KEY (model_id) REFERENCES public.models(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: provider_api_keys fk_provider_api_keys_provider; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.provider_api_keys
ADD CONSTRAINT fk_provider_api_keys_provider FOREIGN KEY (provider_id) REFERENCES public.providers(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: gemini_file_mappings gemini_file_mappings_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.gemini_file_mappings
ADD CONSTRAINT gemini_file_mappings_key_id_fkey FOREIGN KEY (key_id) REFERENCES public.provider_api_keys(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: gemini_file_mappings gemini_file_mappings_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.gemini_file_mappings
ADD CONSTRAINT gemini_file_mappings_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: management_tokens management_tokens_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.management_tokens
ADD CONSTRAINT management_tokens_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: models models_global_model_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.models
ADD CONSTRAINT models_global_model_id_fkey FOREIGN KEY (global_model_id) REFERENCES public.global_models(id);
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: models models_provider_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.models
ADD CONSTRAINT models_provider_id_fkey FOREIGN KEY (provider_id) REFERENCES public.providers(id);
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: payment_callbacks payment_callbacks_payment_order_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.payment_callbacks
ADD CONSTRAINT payment_callbacks_payment_order_id_fkey FOREIGN KEY (payment_order_id) REFERENCES public.payment_orders(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: payment_orders payment_orders_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.payment_orders
ADD CONSTRAINT payment_orders_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: payment_orders payment_orders_wallet_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.payment_orders
ADD CONSTRAINT payment_orders_wallet_id_fkey FOREIGN KEY (wallet_id) REFERENCES public.wallets(id) ON DELETE RESTRICT;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: provider_endpoints provider_endpoints_provider_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.provider_endpoints
ADD CONSTRAINT provider_endpoints_provider_id_fkey FOREIGN KEY (provider_id) REFERENCES public.providers(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: provider_usage_tracking provider_usage_tracking_provider_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.provider_usage_tracking
ADD CONSTRAINT provider_usage_tracking_provider_id_fkey FOREIGN KEY (provider_id) REFERENCES public.providers(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: proxy_node_events proxy_node_events_node_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.proxy_node_events
ADD CONSTRAINT proxy_node_events_node_id_fkey FOREIGN KEY (node_id) REFERENCES public.proxy_nodes(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: proxy_nodes proxy_nodes_registered_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.proxy_nodes
ADD CONSTRAINT proxy_nodes_registered_by_fkey FOREIGN KEY (registered_by) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: refund_requests refund_requests_approved_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.refund_requests
ADD CONSTRAINT refund_requests_approved_by_fkey FOREIGN KEY (approved_by) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: refund_requests refund_requests_payment_order_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.refund_requests
ADD CONSTRAINT refund_requests_payment_order_id_fkey FOREIGN KEY (payment_order_id) REFERENCES public.payment_orders(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: refund_requests refund_requests_processed_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.refund_requests
ADD CONSTRAINT refund_requests_processed_by_fkey FOREIGN KEY (processed_by) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: refund_requests refund_requests_requested_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.refund_requests
ADD CONSTRAINT refund_requests_requested_by_fkey FOREIGN KEY (requested_by) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: refund_requests refund_requests_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.refund_requests
ADD CONSTRAINT refund_requests_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: refund_requests refund_requests_wallet_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.refund_requests
ADD CONSTRAINT refund_requests_wallet_id_fkey FOREIGN KEY (wallet_id) REFERENCES public.wallets(id) ON DELETE RESTRICT;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: request_candidates request_candidates_api_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.request_candidates
ADD CONSTRAINT request_candidates_api_key_id_fkey FOREIGN KEY (api_key_id) REFERENCES public.api_keys(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: request_candidates request_candidates_endpoint_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.request_candidates
ADD CONSTRAINT request_candidates_endpoint_id_fkey FOREIGN KEY (endpoint_id) REFERENCES public.provider_endpoints(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: request_candidates request_candidates_provider_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.request_candidates
ADD CONSTRAINT request_candidates_provider_id_fkey FOREIGN KEY (provider_id) REFERENCES public.providers(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: request_candidates request_candidates_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.request_candidates
ADD CONSTRAINT request_candidates_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: stats_daily_api_key stats_daily_api_key_api_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.stats_daily_api_key
ADD CONSTRAINT stats_daily_api_key_api_key_id_fkey FOREIGN KEY (api_key_id) REFERENCES public.api_keys(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: stats_user_daily stats_user_daily_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.stats_user_daily
ADD CONSTRAINT stats_user_daily_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: usage usage_api_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.usage
ADD CONSTRAINT usage_api_key_id_fkey FOREIGN KEY (api_key_id) REFERENCES public.api_keys(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: usage usage_provider_api_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.usage
ADD CONSTRAINT usage_provider_api_key_id_fkey FOREIGN KEY (provider_api_key_id) REFERENCES public.provider_api_keys(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: usage usage_provider_endpoint_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.usage
ADD CONSTRAINT usage_provider_endpoint_id_fkey FOREIGN KEY (provider_endpoint_id) REFERENCES public.provider_endpoints(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: usage usage_provider_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.usage
ADD CONSTRAINT usage_provider_id_fkey FOREIGN KEY (provider_id) REFERENCES public.providers(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: usage usage_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.usage
ADD CONSTRAINT usage_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: usage usage_wallet_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.usage
ADD CONSTRAINT usage_wallet_id_fkey FOREIGN KEY (wallet_id) REFERENCES public.wallets(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: user_model_usage_counts user_model_usage_counts_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.user_model_usage_counts
ADD CONSTRAINT user_model_usage_counts_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: user_oauth_links user_oauth_links_provider_type_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.user_oauth_links
ADD CONSTRAINT user_oauth_links_provider_type_fkey FOREIGN KEY (provider_type) REFERENCES public.oauth_providers(provider_type) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: user_oauth_links user_oauth_links_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.user_oauth_links
ADD CONSTRAINT user_oauth_links_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: user_preferences user_preferences_default_provider_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.user_preferences
ADD CONSTRAINT user_preferences_default_provider_id_fkey FOREIGN KEY (default_provider_id) REFERENCES public.providers(id);
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: user_preferences user_preferences_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.user_preferences
ADD CONSTRAINT user_preferences_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: user_sessions user_sessions_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.user_sessions
ADD CONSTRAINT user_sessions_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: video_tasks video_tasks_api_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.video_tasks
ADD CONSTRAINT video_tasks_api_key_id_fkey FOREIGN KEY (api_key_id) REFERENCES public.api_keys(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: video_tasks video_tasks_endpoint_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.video_tasks
ADD CONSTRAINT video_tasks_endpoint_id_fkey FOREIGN KEY (endpoint_id) REFERENCES public.provider_endpoints(id);
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: video_tasks video_tasks_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.video_tasks
ADD CONSTRAINT video_tasks_key_id_fkey FOREIGN KEY (key_id) REFERENCES public.provider_api_keys(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: video_tasks video_tasks_provider_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.video_tasks
ADD CONSTRAINT video_tasks_provider_id_fkey FOREIGN KEY (provider_id) REFERENCES public.providers(id);
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: video_tasks video_tasks_remixed_from_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.video_tasks
ADD CONSTRAINT video_tasks_remixed_from_task_id_fkey FOREIGN KEY (remixed_from_task_id) REFERENCES public.video_tasks(id);
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: video_tasks video_tasks_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.video_tasks
ADD CONSTRAINT video_tasks_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: wallet_daily_usage_ledgers wallet_daily_usage_ledgers_wallet_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.wallet_daily_usage_ledgers
ADD CONSTRAINT wallet_daily_usage_ledgers_wallet_id_fkey FOREIGN KEY (wallet_id) REFERENCES public.wallets(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: wallet_transactions wallet_transactions_operator_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.wallet_transactions
ADD CONSTRAINT wallet_transactions_operator_id_fkey FOREIGN KEY (operator_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: wallet_transactions wallet_transactions_wallet_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.wallet_transactions
ADD CONSTRAINT wallet_transactions_wallet_id_fkey FOREIGN KEY (wallet_id) REFERENCES public.wallets(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: wallets wallets_api_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.wallets
ADD CONSTRAINT wallets_api_key_id_fkey FOREIGN KEY (api_key_id) REFERENCES public.api_keys(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: wallets wallets_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.wallets
ADD CONSTRAINT wallets_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;

View File

@@ -0,0 +1,9 @@
-- Restore a normal lookup path before sqlx records this migration in the
-- same transaction. sqlx inserts into `_sqlx_migrations` unqualified.
SELECT pg_catalog.set_config('search_path', 'public', true);
--
-- PostgreSQL database dump complete
--

View File

@@ -0,0 +1,446 @@
-- Baseline v2 extension: usage body blobs
CREATE TABLE IF NOT EXISTS public.usage_body_blobs (
body_ref character varying(160) NOT NULL,
request_id character varying(100) NOT NULL,
body_field character varying(50) NOT NULL,
payload_gzip bytea NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT usage_body_blobs_pkey PRIMARY KEY (body_ref),
CONSTRAINT usage_body_blobs_request_id_field_key UNIQUE (request_id, body_field),
CONSTRAINT usage_body_blobs_request_id_fkey
FOREIGN KEY (request_id)
REFERENCES public.usage(request_id)
ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS ix_usage_body_blobs_request_id
ON public.usage_body_blobs USING btree (request_id);
-- Baseline v2 extension: usage http audits
CREATE TABLE IF NOT EXISTS public.usage_http_audits (
request_id character varying(100) NOT NULL,
request_headers json,
provider_request_headers json,
response_headers json,
client_response_headers json,
request_body_ref character varying(160),
provider_request_body_ref character varying(160),
response_body_ref character varying(160),
client_response_body_ref character varying(160),
request_body_state character varying(32),
provider_request_body_state character varying(32),
response_body_state character varying(32),
client_response_body_state character varying(32),
body_capture_mode character varying(32) DEFAULT 'none' NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT usage_http_audits_pkey PRIMARY KEY (request_id),
CONSTRAINT usage_http_audits_request_id_fkey
FOREIGN KEY (request_id)
REFERENCES public.usage(request_id)
ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS ix_usage_http_audits_updated_at
ON public.usage_http_audits USING btree (updated_at);
-- Baseline v2 extension: usage routing snapshots
CREATE TABLE IF NOT EXISTS public.usage_routing_snapshots (
request_id character varying(100) NOT NULL,
candidate_id character varying(160),
candidate_index integer,
key_name character varying(255),
planner_kind character varying(120),
route_family character varying(80),
route_kind character varying(80),
execution_path character varying(80),
local_execution_runtime_miss_reason character varying(120),
selected_provider_id character varying(100),
selected_endpoint_id character varying(100),
selected_provider_api_key_id character varying(100),
has_format_conversion boolean,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT usage_routing_snapshots_pkey PRIMARY KEY (request_id),
CONSTRAINT usage_routing_snapshots_request_id_fkey
FOREIGN KEY (request_id)
REFERENCES public.usage(request_id)
ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS ix_usage_routing_snapshots_route_family_kind
ON public.usage_routing_snapshots USING btree (route_family, route_kind);
CREATE INDEX IF NOT EXISTS ix_usage_routing_snapshots_candidate_id
ON public.usage_routing_snapshots USING btree (candidate_id);
CREATE TABLE IF NOT EXISTS public.usage_settlement_snapshots (
request_id character varying(100) NOT NULL,
billing_status character varying(20) NOT NULL,
wallet_id character varying(36),
wallet_balance_before numeric(20,8),
wallet_balance_after numeric(20,8),
wallet_recharge_balance_before numeric(20,8),
wallet_recharge_balance_after numeric(20,8),
wallet_gift_balance_before numeric(20,8),
wallet_gift_balance_after numeric(20,8),
provider_monthly_used_usd numeric(20,8),
finalized_at timestamp with time zone,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT usage_settlement_snapshots_pkey PRIMARY KEY (request_id),
CONSTRAINT usage_settlement_snapshots_request_id_fkey
FOREIGN KEY (request_id)
REFERENCES public.usage(request_id)
ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS ix_usage_settlement_snapshots_wallet_id
ON public.usage_settlement_snapshots USING btree (wallet_id);
CREATE INDEX IF NOT EXISTS ix_usage_settlement_snapshots_billing_status
ON public.usage_settlement_snapshots USING btree (billing_status);
ALTER TABLE IF EXISTS public.usage_settlement_snapshots
ADD COLUMN IF NOT EXISTS billing_snapshot_schema_version character varying(20),
ADD COLUMN IF NOT EXISTS billing_snapshot_status character varying(20),
ADD COLUMN IF NOT EXISTS rate_multiplier numeric(10,6),
ADD COLUMN IF NOT EXISTS is_free_tier boolean,
ADD COLUMN IF NOT EXISTS input_price_per_1m numeric(20,8),
ADD COLUMN IF NOT EXISTS output_price_per_1m numeric(20,8),
ADD COLUMN IF NOT EXISTS cache_creation_price_per_1m numeric(20,8),
ADD COLUMN IF NOT EXISTS cache_read_price_per_1m numeric(20,8),
ADD COLUMN IF NOT EXISTS price_per_request numeric(20,8),
ADD COLUMN IF NOT EXISTS settlement_snapshot_schema_version character varying(20),
ADD COLUMN IF NOT EXISTS settlement_snapshot jsonb,
ADD COLUMN IF NOT EXISTS billing_dimensions jsonb,
ADD COLUMN IF NOT EXISTS billing_input_tokens bigint,
ADD COLUMN IF NOT EXISTS billing_effective_input_tokens bigint,
ADD COLUMN IF NOT EXISTS billing_output_tokens bigint,
ADD COLUMN IF NOT EXISTS billing_cache_creation_tokens bigint,
ADD COLUMN IF NOT EXISTS billing_cache_creation_5m_tokens bigint,
ADD COLUMN IF NOT EXISTS billing_cache_creation_1h_tokens bigint,
ADD COLUMN IF NOT EXISTS billing_cache_read_tokens bigint,
ADD COLUMN IF NOT EXISTS billing_total_input_context bigint,
ADD COLUMN IF NOT EXISTS billing_cache_creation_cost_usd numeric(20,8),
ADD COLUMN IF NOT EXISTS billing_cache_read_cost_usd numeric(20,8),
ADD COLUMN IF NOT EXISTS billing_total_cost_usd numeric(20,8),
ADD COLUMN IF NOT EXISTS billing_actual_total_cost_usd numeric(20,8),
ADD COLUMN IF NOT EXISTS billing_pricing_source character varying(50),
ADD COLUMN IF NOT EXISTS billing_rule_id character varying(100),
ADD COLUMN IF NOT EXISTS billing_rule_version character varying(50);
CREATE INDEX IF NOT EXISTS ix_usage_settlement_snapshots_schema_version
ON public.usage_settlement_snapshots USING btree (settlement_snapshot_schema_version);
CREATE INDEX IF NOT EXISTS ix_usage_settlement_snapshots_pricing_source
ON public.usage_settlement_snapshots USING btree (billing_pricing_source);
CREATE OR REPLACE VIEW public.usage_billing_facts AS
SELECT
usage_rows.id,
usage_rows.request_id,
usage_rows.user_id,
usage_rows.api_key_id,
usage_rows.username,
usage_rows.api_key_name,
usage_rows.provider_name,
usage_rows.model,
usage_rows.target_model,
usage_rows.provider_id,
usage_rows.provider_endpoint_id,
usage_rows.provider_api_key_id,
usage_rows.request_type,
usage_rows.api_format,
usage_rows.api_family,
usage_rows.endpoint_kind,
usage_rows.endpoint_api_format,
usage_rows.provider_api_family,
usage_rows.provider_endpoint_kind,
COALESCE(usage_rows.has_format_conversion, FALSE) AS has_format_conversion,
COALESCE(usage_rows.is_stream, FALSE) AS is_stream,
usage_rows.status_code,
usage_rows.error_message,
usage_rows.error_category,
usage_rows.response_time_ms,
usage_rows.first_byte_time_ms,
usage_rows.status,
COALESCE(settlement.billing_status, usage_rows.billing_status) AS billing_status,
usage_rows.created_at,
COALESCE(settlement.finalized_at, usage_rows.finalized_at) AS finalized_at,
GREATEST(COALESCE(settlement.billing_input_tokens, usage_rows.input_tokens, 0), 0)::bigint
AS input_tokens,
GREATEST(
COALESCE(
settlement.billing_effective_input_tokens,
CASE
WHEN GREATEST(COALESCE(usage_rows.input_tokens, 0), 0) <= 0 THEN 0
WHEN GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0) <= 0
THEN GREATEST(COALESCE(usage_rows.input_tokens, 0), 0)
WHEN split_part(lower(COALESCE(COALESCE(usage_rows.endpoint_api_format, usage_rows.api_format), '')), ':', 1)
IN ('openai', 'gemini', 'google')
THEN GREATEST(
GREATEST(COALESCE(usage_rows.input_tokens, 0), 0)
- GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0),
0
)
ELSE GREATEST(COALESCE(usage_rows.input_tokens, 0), 0)
END
),
0
)::bigint AS effective_input_tokens,
GREATEST(COALESCE(settlement.billing_output_tokens, usage_rows.output_tokens, 0), 0)::bigint
AS output_tokens,
GREATEST(
COALESCE(
settlement.billing_cache_creation_tokens,
CASE
WHEN COALESCE(usage_rows.cache_creation_input_tokens, 0) = 0
AND (
COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
) > 0
THEN COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
ELSE COALESCE(usage_rows.cache_creation_input_tokens, 0)
END,
0
),
0
)::bigint AS cache_creation_input_tokens,
GREATEST(
COALESCE(
settlement.billing_cache_creation_5m_tokens,
usage_rows.cache_creation_input_tokens_5m,
0
),
0
)::bigint AS cache_creation_input_tokens_5m,
GREATEST(
COALESCE(
settlement.billing_cache_creation_1h_tokens,
usage_rows.cache_creation_input_tokens_1h,
0
),
0
)::bigint AS cache_creation_input_tokens_1h,
GREATEST(COALESCE(settlement.billing_cache_read_tokens, usage_rows.cache_read_input_tokens, 0), 0)::bigint
AS cache_read_input_tokens,
GREATEST(
COALESCE(
CASE
WHEN settlement.billing_input_tokens IS NOT NULL
OR settlement.billing_output_tokens IS NOT NULL
OR settlement.billing_cache_creation_tokens IS NOT NULL
OR settlement.billing_cache_creation_5m_tokens IS NOT NULL
OR settlement.billing_cache_creation_1h_tokens IS NOT NULL
OR settlement.billing_cache_read_tokens IS NOT NULL
THEN COALESCE(settlement.billing_input_tokens, 0)
+ COALESCE(settlement.billing_output_tokens, 0)
+ COALESCE(
settlement.billing_cache_creation_tokens,
COALESCE(settlement.billing_cache_creation_5m_tokens, 0)
+ COALESCE(settlement.billing_cache_creation_1h_tokens, 0),
0
)
+ COALESCE(settlement.billing_cache_read_tokens, 0)
END,
usage_rows.total_tokens,
0
),
0
)::bigint AS total_tokens,
GREATEST(
COALESCE(
settlement.billing_total_input_context,
CASE
WHEN split_part(lower(COALESCE(COALESCE(usage_rows.endpoint_api_format, usage_rows.api_format), '')), ':', 1)
IN ('claude', 'anthropic')
THEN GREATEST(COALESCE(usage_rows.input_tokens, 0), 0)
+ CASE
WHEN COALESCE(usage_rows.cache_creation_input_tokens, 0) = 0
AND (
COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
) > 0
THEN COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
ELSE COALESCE(usage_rows.cache_creation_input_tokens, 0)
END
+ GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0)
WHEN split_part(lower(COALESCE(COALESCE(usage_rows.endpoint_api_format, usage_rows.api_format), '')), ':', 1)
IN ('openai', 'gemini', 'google')
THEN CASE
WHEN GREATEST(COALESCE(usage_rows.input_tokens, 0), 0) <= 0 THEN 0
WHEN GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0) <= 0
THEN GREATEST(COALESCE(usage_rows.input_tokens, 0), 0)
ELSE GREATEST(
GREATEST(COALESCE(usage_rows.input_tokens, 0), 0)
- GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0),
0
)
END
+ GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0)
ELSE GREATEST(COALESCE(usage_rows.input_tokens, 0), 0)
+ CASE
WHEN COALESCE(usage_rows.cache_creation_input_tokens, 0) = 0
AND (
COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
) > 0
THEN COALESCE(usage_rows.cache_creation_input_tokens_5m, 0)
+ COALESCE(usage_rows.cache_creation_input_tokens_1h, 0)
ELSE COALESCE(usage_rows.cache_creation_input_tokens, 0)
END
+ GREATEST(COALESCE(usage_rows.cache_read_input_tokens, 0), 0)
END,
0
),
0
)::bigint AS total_input_context,
COALESCE(CAST(usage_rows.input_cost_usd AS DOUBLE PRECISION), 0) AS input_cost_usd,
COALESCE(CAST(usage_rows.output_cost_usd AS DOUBLE PRECISION), 0) AS output_cost_usd,
COALESCE(
CAST(settlement.billing_cache_creation_cost_usd AS DOUBLE PRECISION),
CAST(usage_rows.cache_creation_cost_usd AS DOUBLE PRECISION),
0
) AS cache_creation_cost_usd,
COALESCE(
CAST(settlement.billing_cache_read_cost_usd AS DOUBLE PRECISION),
CAST(usage_rows.cache_read_cost_usd AS DOUBLE PRECISION),
0
) AS cache_read_cost_usd,
COALESCE(
CAST(settlement.billing_total_cost_usd AS DOUBLE PRECISION),
CAST(usage_rows.total_cost_usd AS DOUBLE PRECISION),
0
) AS total_cost_usd,
COALESCE(
CAST(settlement.billing_actual_total_cost_usd AS DOUBLE PRECISION),
CAST(usage_rows.actual_total_cost_usd AS DOUBLE PRECISION),
0
) AS actual_total_cost_usd,
COALESCE(
CAST(settlement.output_price_per_1m AS DOUBLE PRECISION),
CAST(usage_rows.output_price_per_1m AS DOUBLE PRECISION)
) AS output_price_per_1m,
COALESCE(
CAST(settlement.input_price_per_1m AS DOUBLE PRECISION),
CAST(usage_rows.input_price_per_1m AS DOUBLE PRECISION)
) AS input_price_per_1m,
COALESCE(
CAST(settlement.cache_creation_price_per_1m AS DOUBLE PRECISION),
CAST(usage_rows.cache_creation_price_per_1m AS DOUBLE PRECISION)
) AS cache_creation_price_per_1m,
COALESCE(
CAST(settlement.cache_read_price_per_1m AS DOUBLE PRECISION),
CAST(usage_rows.cache_read_price_per_1m AS DOUBLE PRECISION)
) AS cache_read_price_per_1m,
COALESCE(
CAST(settlement.price_per_request AS DOUBLE PRECISION),
CAST(usage_rows.price_per_request AS DOUBLE PRECISION)
) AS price_per_request,
settlement.billing_pricing_source,
settlement.billing_rule_id,
settlement.billing_rule_version,
COALESCE(usage_rows.upstream_is_stream, COALESCE(usage_rows.is_stream, FALSE)) AS upstream_is_stream
FROM public."usage" AS usage_rows
LEFT JOIN public.usage_settlement_snapshots AS settlement
ON settlement.request_id = usage_rows.request_id;
COMMENT ON VIEW public.usage_billing_facts IS
'Canonical billing read model. Token/cost fields prefer usage_settlement_snapshots.billing_* and fall back to deprecated usage mirrors for legacy rows.';
COMMENT ON COLUMN public.usage_billing_facts.upstream_is_stream IS
'Resolved upstream stream mode from public.usage.upstream_is_stream, falling back to usage.is_stream for legacy rows.';
COMMENT ON COLUMN public.usage.input_tokens IS
'DEPRECATED: billing dimension mirror. Use public.usage_settlement_snapshots.billing_input_tokens or public.usage_billing_facts.input_tokens.';
COMMENT ON COLUMN public.usage.output_tokens IS
'DEPRECATED: billing dimension mirror. Use public.usage_settlement_snapshots.billing_output_tokens or public.usage_billing_facts.output_tokens.';
COMMENT ON COLUMN public.usage.total_tokens IS
'DEPRECATED: billing dimension mirror. Use public.usage_billing_facts.total_tokens.';
COMMENT ON COLUMN public.usage.cache_creation_input_tokens IS
'DEPRECATED: billing dimension mirror. Use public.usage_settlement_snapshots.billing_cache_creation_tokens or public.usage_billing_facts.cache_creation_input_tokens.';
COMMENT ON COLUMN public.usage.cache_creation_input_tokens_5m IS
'DEPRECATED: billing dimension mirror. Use public.usage_settlement_snapshots.billing_cache_creation_5m_tokens or public.usage_billing_facts.cache_creation_input_tokens_5m.';
COMMENT ON COLUMN public.usage.cache_creation_input_tokens_1h IS
'DEPRECATED: billing dimension mirror. Use public.usage_settlement_snapshots.billing_cache_creation_1h_tokens or public.usage_billing_facts.cache_creation_input_tokens_1h.';
COMMENT ON COLUMN public.usage.cache_read_input_tokens IS
'DEPRECATED: billing dimension mirror. Use public.usage_settlement_snapshots.billing_cache_read_tokens or public.usage_billing_facts.cache_read_input_tokens.';
COMMENT ON COLUMN public.usage.cache_creation_cost_usd IS
'DEPRECATED: billing cost mirror. Use public.usage_settlement_snapshots.billing_cache_creation_cost_usd or public.usage_billing_facts.cache_creation_cost_usd.';
COMMENT ON COLUMN public.usage.cache_read_cost_usd IS
'DEPRECATED: billing cost mirror. Use public.usage_settlement_snapshots.billing_cache_read_cost_usd or public.usage_billing_facts.cache_read_cost_usd.';
COMMENT ON COLUMN public.usage.total_cost_usd IS
'DEPRECATED: billing cost mirror. Use public.usage_settlement_snapshots.billing_total_cost_usd or public.usage_billing_facts.total_cost_usd.';
COMMENT ON COLUMN public.usage.actual_total_cost_usd IS
'DEPRECATED: billing cost mirror. Use public.usage_settlement_snapshots.billing_actual_total_cost_usd or public.usage_billing_facts.actual_total_cost_usd.';
COMMENT ON COLUMN public.usage.wallet_id IS
'DEPRECATED: settlement owner moved to public.usage_settlement_snapshots.wallet_id. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.wallet_balance_before IS
'DEPRECATED: settlement owner moved to public.usage_settlement_snapshots.wallet_balance_before. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.wallet_balance_after IS
'DEPRECATED: settlement owner moved to public.usage_settlement_snapshots.wallet_balance_after. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.wallet_recharge_balance_before IS
'DEPRECATED: settlement owner moved to public.usage_settlement_snapshots.wallet_recharge_balance_before. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.wallet_recharge_balance_after IS
'DEPRECATED: settlement owner moved to public.usage_settlement_snapshots.wallet_recharge_balance_after. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.wallet_gift_balance_before IS
'DEPRECATED: settlement owner moved to public.usage_settlement_snapshots.wallet_gift_balance_before. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.wallet_gift_balance_after IS
'DEPRECATED: settlement owner moved to public.usage_settlement_snapshots.wallet_gift_balance_after. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.rate_multiplier IS
'DEPRECATED: settlement pricing owner moved to public.usage_settlement_snapshots.rate_multiplier. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.input_price_per_1m IS
'DEPRECATED: settlement pricing owner moved to public.usage_settlement_snapshots.input_price_per_1m. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.output_price_per_1m IS
'DEPRECATED: settlement pricing owner moved to public.usage_settlement_snapshots.output_price_per_1m. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.cache_creation_price_per_1m IS
'DEPRECATED: settlement pricing owner moved to public.usage_settlement_snapshots.cache_creation_price_per_1m. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.cache_read_price_per_1m IS
'DEPRECATED: settlement pricing owner moved to public.usage_settlement_snapshots.cache_read_price_per_1m. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.price_per_request IS
'DEPRECATED: settlement pricing owner moved to public.usage_settlement_snapshots.price_per_request. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.username IS
'DEPRECATED: display cache only. Prefer join-time lookup from user/auth records. Legacy compatibility only.';
COMMENT ON COLUMN public.usage.api_key_name IS
'DEPRECATED: display cache only. Prefer join-time lookup from API key records. Legacy compatibility only.';
COMMENT ON COLUMN public.usage.billing_status IS
'DEPRECATED: authoritative owner moved to public.usage_settlement_snapshots.billing_status. Compatibility/index mirror only; do not write new values.';
COMMENT ON COLUMN public.usage.finalized_at IS
'DEPRECATED: authoritative owner moved to public.usage_settlement_snapshots.finalized_at. Compatibility/index mirror only; do not write new values.';
COMMENT ON COLUMN public.usage.request_headers IS
'DEPRECATED: HTTP audit owner moved to public.usage_http_audits.request_headers. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.provider_request_headers IS
'DEPRECATED: HTTP audit owner moved to public.usage_http_audits.provider_request_headers. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.response_headers IS
'DEPRECATED: HTTP audit owner moved to public.usage_http_audits.response_headers. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.client_response_headers IS
'DEPRECATED: HTTP audit owner moved to public.usage_http_audits.client_response_headers. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.request_body IS
'DEPRECATED: HTTP body owner moved to public.usage_body_blobs plus public.usage_http_audits.request_body_ref. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.request_body_compressed IS
'DEPRECATED: HTTP body owner moved to public.usage_body_blobs plus public.usage_http_audits.request_body_ref. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.provider_request_body IS
'DEPRECATED: HTTP body owner moved to public.usage_body_blobs plus public.usage_http_audits.provider_request_body_ref. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.provider_request_body_compressed IS
'DEPRECATED: HTTP body owner moved to public.usage_body_blobs plus public.usage_http_audits.provider_request_body_ref. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.response_body IS
'DEPRECATED: HTTP body owner moved to public.usage_body_blobs plus public.usage_http_audits.response_body_ref. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.response_body_compressed IS
'DEPRECATED: HTTP body owner moved to public.usage_body_blobs plus public.usage_http_audits.response_body_ref. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.client_response_body IS
'DEPRECATED: HTTP body owner moved to public.usage_body_blobs plus public.usage_http_audits.client_response_body_ref. Legacy compatibility only; do not write new values.';
COMMENT ON COLUMN public.usage.client_response_body_compressed IS
'DEPRECATED: HTTP body owner moved to public.usage_body_blobs plus public.usage_http_audits.client_response_body_ref. Legacy compatibility only; do not write new values.';

View File

@@ -0,0 +1,132 @@
CREATE TABLE IF NOT EXISTS public.redeem_code_batches (
id character varying(36) NOT NULL,
name character varying(120) NOT NULL,
amount_usd numeric(20,8) NOT NULL,
currency character varying(3) DEFAULT 'USD'::character varying NOT NULL,
balance_bucket character varying(20) DEFAULT 'gift'::character varying NOT NULL,
total_count integer NOT NULL,
status character varying(20) DEFAULT 'active'::character varying NOT NULL,
description text,
created_by character varying(36),
expires_at timestamp with time zone,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
CONSTRAINT ck_redeem_code_batches_amount_positive CHECK ((amount_usd > (0)::numeric)),
CONSTRAINT ck_redeem_code_batches_total_count_positive CHECK ((total_count > 0))
);
CREATE TABLE IF NOT EXISTS public.redeem_codes (
id character varying(36) NOT NULL,
batch_id character varying(36) NOT NULL,
code_hash character varying(64) NOT NULL,
code_prefix character varying(8) NOT NULL,
code_suffix character varying(8) NOT NULL,
status character varying(20) DEFAULT 'active'::character varying NOT NULL,
redeemed_by_user_id character varying(36),
redeemed_wallet_id character varying(36),
redeemed_payment_order_id character varying(36),
redeemed_at timestamp with time zone,
disabled_by character varying(36),
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL
);
DO $mig$ BEGIN
ALTER TABLE ONLY public.redeem_code_batches
ADD CONSTRAINT redeem_code_batches_pkey PRIMARY KEY (id);
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
DO $mig$ BEGIN
ALTER TABLE ONLY public.redeem_codes
ADD CONSTRAINT redeem_codes_pkey PRIMARY KEY (id);
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
DO $mig$ BEGIN
ALTER TABLE ONLY public.redeem_codes
ADD CONSTRAINT uq_redeem_codes_code_hash UNIQUE (code_hash);
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
CREATE INDEX IF NOT EXISTS idx_redeem_code_batches_status
ON public.redeem_code_batches USING btree (status, created_at);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_batch_created
ON public.redeem_codes USING btree (batch_id, created_at);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_status
ON public.redeem_codes USING btree (status, updated_at);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_redeemed_user
ON public.redeem_codes USING btree (redeemed_by_user_id, redeemed_at);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_redeemed_order
ON public.redeem_codes USING btree (redeemed_payment_order_id);
DO $mig$ BEGIN
ALTER TABLE ONLY public.redeem_code_batches
ADD CONSTRAINT redeem_code_batches_created_by_fkey FOREIGN KEY (created_by) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
END $mig$;
DO $mig$ BEGIN
ALTER TABLE ONLY public.redeem_codes
ADD CONSTRAINT redeem_codes_batch_id_fkey FOREIGN KEY (batch_id) REFERENCES public.redeem_code_batches(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
END $mig$;
DO $mig$ BEGIN
ALTER TABLE ONLY public.redeem_codes
ADD CONSTRAINT redeem_codes_redeemed_by_user_id_fkey FOREIGN KEY (redeemed_by_user_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
END $mig$;
DO $mig$ BEGIN
ALTER TABLE ONLY public.redeem_codes
ADD CONSTRAINT redeem_codes_redeemed_wallet_id_fkey FOREIGN KEY (redeemed_wallet_id) REFERENCES public.wallets(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
END $mig$;
DO $mig$ BEGIN
ALTER TABLE ONLY public.redeem_codes
ADD CONSTRAINT redeem_codes_redeemed_payment_order_id_fkey FOREIGN KEY (redeemed_payment_order_id) REFERENCES public.payment_orders(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
END $mig$;
DO $mig$ BEGIN
ALTER TABLE ONLY public.redeem_codes
ADD CONSTRAINT redeem_codes_disabled_by_fkey FOREIGN KEY (disabled_by) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
END $mig$;
ALTER TABLE public.stats_user_daily
ADD COLUMN IF NOT EXISTS actual_total_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
ADD COLUMN IF NOT EXISTS response_time_sum_ms double precision DEFAULT '0'::double precision NOT NULL,
ADD COLUMN IF NOT EXISTS response_time_samples bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS effective_input_tokens bigint DEFAULT '0'::bigint NOT NULL,
ADD COLUMN IF NOT EXISTS total_input_context bigint DEFAULT '0'::bigint NOT NULL,
ADD COLUMN IF NOT EXISTS cache_creation_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
ADD COLUMN IF NOT EXISTS cache_read_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL;
ALTER TABLE public.stats_hourly_user
ADD COLUMN IF NOT EXISTS cache_creation_tokens bigint DEFAULT '0'::bigint NOT NULL,
ADD COLUMN IF NOT EXISTS cache_read_tokens bigint DEFAULT '0'::bigint NOT NULL,
ADD COLUMN IF NOT EXISTS actual_total_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
ADD COLUMN IF NOT EXISTS response_time_sum_ms double precision DEFAULT '0'::double precision NOT NULL,
ADD COLUMN IF NOT EXISTS response_time_samples bigint DEFAULT 0 NOT NULL;

View File

@@ -0,0 +1,324 @@
CREATE TABLE IF NOT EXISTS public.stats_user_summary (
id character varying(36) NOT NULL,
user_id character varying(36) NOT NULL,
username character varying(100),
cutoff_date timestamp with time zone NOT NULL,
all_time_requests integer DEFAULT 0 NOT NULL,
all_time_success_requests integer DEFAULT 0 NOT NULL,
all_time_error_requests integer DEFAULT 0 NOT NULL,
all_time_input_tokens bigint DEFAULT '0'::bigint NOT NULL,
all_time_output_tokens bigint DEFAULT '0'::bigint NOT NULL,
all_time_cache_creation_tokens bigint DEFAULT '0'::bigint NOT NULL,
all_time_cache_read_tokens bigint DEFAULT '0'::bigint NOT NULL,
all_time_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
all_time_actual_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
active_days integer DEFAULT 0 NOT NULL,
first_active_date timestamp with time zone,
last_active_date timestamp with time zone,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT stats_user_summary_pkey PRIMARY KEY (id),
CONSTRAINT uq_stats_user_summary_user_id UNIQUE (user_id),
CONSTRAINT stats_user_summary_user_id_fkey
FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_stats_user_summary_cutoff_date
ON public.stats_user_summary USING btree (cutoff_date);
ALTER TABLE public.stats_daily
ADD COLUMN IF NOT EXISTS effective_input_tokens bigint DEFAULT '0'::bigint NOT NULL,
ADD COLUMN IF NOT EXISTS total_input_context bigint DEFAULT '0'::bigint NOT NULL,
ADD COLUMN IF NOT EXISTS response_time_sum_ms double precision DEFAULT '0'::double precision NOT NULL,
ADD COLUMN IF NOT EXISTS response_time_samples bigint DEFAULT 0 NOT NULL;
ALTER TABLE public.stats_daily_model
ADD COLUMN IF NOT EXISTS response_time_sum_ms double precision DEFAULT '0'::double precision NOT NULL,
ADD COLUMN IF NOT EXISTS response_time_samples bigint DEFAULT 0 NOT NULL;
CREATE TABLE IF NOT EXISTS public.stats_user_daily_model (
id character varying(36) NOT NULL,
user_id character varying(36) NOT NULL,
username character varying(100),
date timestamp with time zone NOT NULL,
model character varying(100) NOT NULL,
total_requests integer DEFAULT 0 NOT NULL,
input_tokens bigint DEFAULT '0'::bigint NOT NULL,
output_tokens bigint DEFAULT '0'::bigint NOT NULL,
total_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
response_time_sum_ms double precision DEFAULT '0'::double precision NOT NULL,
response_time_samples bigint DEFAULT 0 NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT stats_user_daily_model_pkey PRIMARY KEY (id),
CONSTRAINT uq_stats_user_daily_model_user_date_model UNIQUE (user_id, date, model),
CONSTRAINT stats_user_daily_model_user_id_fkey
FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_stats_user_daily_model_date
ON public.stats_user_daily_model USING btree (date);
CREATE INDEX IF NOT EXISTS idx_stats_user_daily_model_user_id
ON public.stats_user_daily_model USING btree (user_id);
ALTER TABLE public.stats_hourly
ADD COLUMN IF NOT EXISTS response_time_sum_ms double precision DEFAULT '0'::double precision NOT NULL,
ADD COLUMN IF NOT EXISTS response_time_samples bigint DEFAULT 0 NOT NULL;
ALTER TABLE public.stats_hourly_model
ADD COLUMN IF NOT EXISTS response_time_sum_ms double precision DEFAULT '0'::double precision NOT NULL,
ADD COLUMN IF NOT EXISTS response_time_samples bigint DEFAULT 0 NOT NULL;
CREATE TABLE IF NOT EXISTS public.stats_hourly_user_model (
id character varying(36) NOT NULL,
hour_utc timestamp with time zone NOT NULL,
user_id character varying(36) NOT NULL,
model character varying(100) NOT NULL,
total_requests integer DEFAULT 0 NOT NULL,
input_tokens bigint DEFAULT '0'::bigint NOT NULL,
output_tokens bigint DEFAULT '0'::bigint NOT NULL,
total_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
response_time_sum_ms double precision DEFAULT '0'::double precision NOT NULL,
response_time_samples bigint DEFAULT 0 NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT stats_hourly_user_model_pkey PRIMARY KEY (id),
CONSTRAINT uq_stats_hourly_user_model UNIQUE (hour_utc, user_id, model),
CONSTRAINT stats_hourly_user_model_user_id_fkey
FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_stats_hourly_user_model_hour
ON public.stats_hourly_user_model USING btree (hour_utc);
CREATE INDEX IF NOT EXISTS idx_stats_hourly_user_model_user_hour
ON public.stats_hourly_user_model USING btree (user_id, hour_utc);
CREATE TABLE IF NOT EXISTS public.schema_backfills (
version bigint NOT NULL,
description text NOT NULL,
success boolean NOT NULL DEFAULT TRUE,
checksum bytea NOT NULL,
execution_time bigint NOT NULL DEFAULT 0,
applied_at timestamp with time zone NOT NULL DEFAULT now(),
CONSTRAINT schema_backfills_pkey PRIMARY KEY (version)
);
CREATE INDEX IF NOT EXISTS idx_schema_backfills_applied_at
ON public.schema_backfills USING btree (applied_at DESC);
ALTER TABLE public.stats_user_daily_model
ADD COLUMN IF NOT EXISTS success_requests integer DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS effective_input_tokens bigint DEFAULT '0'::bigint NOT NULL,
ADD COLUMN IF NOT EXISTS total_tokens bigint DEFAULT '0'::bigint NOT NULL,
ADD COLUMN IF NOT EXISTS total_input_context bigint DEFAULT '0'::bigint NOT NULL,
ADD COLUMN IF NOT EXISTS cache_creation_tokens bigint DEFAULT '0'::bigint NOT NULL,
ADD COLUMN IF NOT EXISTS cache_creation_ephemeral_5m_tokens bigint DEFAULT '0'::bigint NOT NULL,
ADD COLUMN IF NOT EXISTS cache_creation_ephemeral_1h_tokens bigint DEFAULT '0'::bigint NOT NULL,
ADD COLUMN IF NOT EXISTS cache_read_tokens bigint DEFAULT '0'::bigint NOT NULL,
ADD COLUMN IF NOT EXISTS actual_total_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
ADD COLUMN IF NOT EXISTS successful_response_time_sum_ms double precision DEFAULT '0'::double precision NOT NULL,
ADD COLUMN IF NOT EXISTS successful_response_time_samples bigint DEFAULT 0 NOT NULL;
CREATE TABLE IF NOT EXISTS public.stats_user_daily_provider (
id character varying(36) NOT NULL,
user_id character varying(36) NOT NULL,
username character varying(100),
date timestamp with time zone NOT NULL,
provider_name character varying(100) NOT NULL,
total_requests integer DEFAULT 0 NOT NULL,
success_requests integer DEFAULT 0 NOT NULL,
input_tokens bigint DEFAULT '0'::bigint NOT NULL,
effective_input_tokens bigint DEFAULT '0'::bigint NOT NULL,
output_tokens bigint DEFAULT '0'::bigint NOT NULL,
total_tokens bigint DEFAULT '0'::bigint NOT NULL,
total_input_context bigint DEFAULT '0'::bigint NOT NULL,
cache_creation_tokens bigint DEFAULT '0'::bigint NOT NULL,
cache_creation_ephemeral_5m_tokens bigint DEFAULT '0'::bigint NOT NULL,
cache_creation_ephemeral_1h_tokens bigint DEFAULT '0'::bigint NOT NULL,
cache_read_tokens bigint DEFAULT '0'::bigint NOT NULL,
total_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
actual_total_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
response_time_sum_ms double precision DEFAULT '0'::double precision NOT NULL,
response_time_samples bigint DEFAULT 0 NOT NULL,
successful_response_time_sum_ms double precision DEFAULT '0'::double precision NOT NULL,
successful_response_time_samples bigint DEFAULT 0 NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT stats_user_daily_provider_pkey PRIMARY KEY (id),
CONSTRAINT uq_stats_user_daily_provider_user_date_provider UNIQUE (user_id, date, provider_name),
CONSTRAINT stats_user_daily_provider_user_id_fkey
FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_stats_user_daily_provider_date
ON public.stats_user_daily_provider USING btree (date);
CREATE INDEX IF NOT EXISTS idx_stats_user_daily_provider_user_id
ON public.stats_user_daily_provider USING btree (user_id);
CREATE TABLE IF NOT EXISTS public.stats_user_daily_api_format (
id character varying(36) NOT NULL,
user_id character varying(36) NOT NULL,
username character varying(100),
date timestamp with time zone NOT NULL,
api_format character varying(50) NOT NULL,
total_requests integer DEFAULT 0 NOT NULL,
success_requests integer DEFAULT 0 NOT NULL,
input_tokens bigint DEFAULT '0'::bigint NOT NULL,
effective_input_tokens bigint DEFAULT '0'::bigint NOT NULL,
output_tokens bigint DEFAULT '0'::bigint NOT NULL,
total_tokens bigint DEFAULT '0'::bigint NOT NULL,
total_input_context bigint DEFAULT '0'::bigint NOT NULL,
cache_creation_tokens bigint DEFAULT '0'::bigint NOT NULL,
cache_creation_ephemeral_5m_tokens bigint DEFAULT '0'::bigint NOT NULL,
cache_creation_ephemeral_1h_tokens bigint DEFAULT '0'::bigint NOT NULL,
cache_read_tokens bigint DEFAULT '0'::bigint NOT NULL,
total_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
actual_total_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
response_time_sum_ms double precision DEFAULT '0'::double precision NOT NULL,
response_time_samples bigint DEFAULT 0 NOT NULL,
successful_response_time_sum_ms double precision DEFAULT '0'::double precision NOT NULL,
successful_response_time_samples bigint DEFAULT 0 NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT stats_user_daily_api_format_pkey PRIMARY KEY (id),
CONSTRAINT uq_stats_user_daily_api_format_user_date_api_format UNIQUE (user_id, date, api_format),
CONSTRAINT stats_user_daily_api_format_user_id_fkey
FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_stats_user_daily_api_format_date
ON public.stats_user_daily_api_format USING btree (date);
CREATE INDEX IF NOT EXISTS idx_stats_user_daily_api_format_user_id
ON public.stats_user_daily_api_format USING btree (user_id);
CREATE TABLE IF NOT EXISTS public.stats_daily_model_provider (
id character varying(36) NOT NULL,
date timestamp with time zone NOT NULL,
model character varying(100) NOT NULL,
provider_name character varying(100) NOT NULL,
total_requests integer DEFAULT 0 NOT NULL,
total_tokens bigint DEFAULT '0'::bigint NOT NULL,
total_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
response_time_sum_ms double precision DEFAULT '0'::double precision NOT NULL,
response_time_samples bigint DEFAULT 0 NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT stats_daily_model_provider_pkey PRIMARY KEY (id),
CONSTRAINT uq_stats_daily_model_provider UNIQUE (date, model, provider_name)
);
CREATE INDEX IF NOT EXISTS idx_stats_daily_model_provider_date
ON public.stats_daily_model_provider USING btree (date);
CREATE INDEX IF NOT EXISTS idx_stats_daily_model_provider_date_model_provider
ON public.stats_daily_model_provider USING btree (date, model, provider_name);
CREATE TABLE IF NOT EXISTS public.stats_user_daily_model_provider (
id character varying(36) NOT NULL,
user_id character varying(36) NOT NULL,
username character varying(100),
date timestamp with time zone NOT NULL,
model character varying(100) NOT NULL,
provider_name character varying(100) NOT NULL,
total_requests integer DEFAULT 0 NOT NULL,
total_tokens bigint DEFAULT '0'::bigint NOT NULL,
total_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
response_time_sum_ms double precision DEFAULT '0'::double precision NOT NULL,
response_time_samples bigint DEFAULT 0 NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT stats_user_daily_model_provider_pkey PRIMARY KEY (id),
CONSTRAINT uq_stats_user_daily_model_provider UNIQUE (user_id, date, model, provider_name),
CONSTRAINT stats_user_daily_model_provider_user_id_fkey
FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_stats_user_daily_model_provider_date
ON public.stats_user_daily_model_provider USING btree (date);
CREATE INDEX IF NOT EXISTS idx_stats_user_daily_model_provider_user_date
ON public.stats_user_daily_model_provider USING btree (user_id, date);
ALTER TABLE public.stats_daily
ADD COLUMN IF NOT EXISTS cache_creation_ephemeral_5m_tokens bigint DEFAULT '0'::bigint NOT NULL,
ADD COLUMN IF NOT EXISTS cache_creation_ephemeral_1h_tokens bigint DEFAULT '0'::bigint NOT NULL;
ALTER TABLE public.stats_user_daily
ADD COLUMN IF NOT EXISTS cache_creation_ephemeral_5m_tokens bigint DEFAULT '0'::bigint NOT NULL,
ADD COLUMN IF NOT EXISTS cache_creation_ephemeral_1h_tokens bigint DEFAULT '0'::bigint NOT NULL;
ALTER TABLE public.stats_daily_model
ADD COLUMN IF NOT EXISTS cache_creation_ephemeral_5m_tokens bigint DEFAULT '0'::bigint NOT NULL,
ADD COLUMN IF NOT EXISTS cache_creation_ephemeral_1h_tokens bigint DEFAULT '0'::bigint NOT NULL;
ALTER TABLE public.stats_daily
ADD COLUMN IF NOT EXISTS cache_hit_total_requests bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS cache_hit_requests bigint DEFAULT 0 NOT NULL;
ALTER TABLE public.stats_hourly
ADD COLUMN IF NOT EXISTS cache_hit_total_requests bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS cache_hit_requests bigint DEFAULT 0 NOT NULL;
ALTER TABLE public.stats_daily
ADD COLUMN IF NOT EXISTS completed_total_requests bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS completed_cache_hit_requests bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS completed_input_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS completed_cache_creation_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS completed_cache_read_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS completed_total_input_context bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS completed_cache_creation_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
ADD COLUMN IF NOT EXISTS completed_cache_read_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL;
ALTER TABLE public.stats_hourly
ADD COLUMN IF NOT EXISTS completed_total_requests bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS completed_cache_hit_requests bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS completed_input_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS completed_cache_creation_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS completed_cache_read_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS completed_total_input_context bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS completed_cache_creation_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
ADD COLUMN IF NOT EXISTS completed_cache_read_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL;
ALTER TABLE public.stats_daily
ADD COLUMN IF NOT EXISTS settled_total_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
ADD COLUMN IF NOT EXISTS settled_total_requests bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_input_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_output_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_cache_creation_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_cache_read_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_first_finalized_at_unix_secs bigint,
ADD COLUMN IF NOT EXISTS settled_last_finalized_at_unix_secs bigint;
ALTER TABLE public.stats_hourly
ADD COLUMN IF NOT EXISTS settled_total_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
ADD COLUMN IF NOT EXISTS settled_total_requests bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_input_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_output_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_cache_creation_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_cache_read_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_first_finalized_at_unix_secs bigint,
ADD COLUMN IF NOT EXISTS settled_last_finalized_at_unix_secs bigint;
ALTER TABLE public.stats_user_daily
ADD COLUMN IF NOT EXISTS settled_total_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
ADD COLUMN IF NOT EXISTS settled_total_requests bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_input_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_output_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_cache_creation_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_cache_read_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_first_finalized_at_unix_secs bigint,
ADD COLUMN IF NOT EXISTS settled_last_finalized_at_unix_secs bigint;
ALTER TABLE public.stats_hourly_user
ADD COLUMN IF NOT EXISTS settled_total_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
ADD COLUMN IF NOT EXISTS settled_total_requests bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_input_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_output_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_cache_creation_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_cache_read_tokens bigint DEFAULT 0 NOT NULL,
ADD COLUMN IF NOT EXISTS settled_first_finalized_at_unix_secs bigint,
ADD COLUMN IF NOT EXISTS settled_last_finalized_at_unix_secs bigint;

View File

@@ -0,0 +1,173 @@
CREATE TABLE IF NOT EXISTS public.stats_daily_cost_savings (
id character varying(36) NOT NULL,
date timestamp with time zone NOT NULL,
cache_read_tokens bigint DEFAULT '0'::bigint NOT NULL,
cache_read_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
cache_creation_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
estimated_full_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT stats_daily_cost_savings_pkey PRIMARY KEY (id),
CONSTRAINT uq_stats_daily_cost_savings_date UNIQUE (date)
);
CREATE INDEX IF NOT EXISTS idx_stats_daily_cost_savings_date
ON public.stats_daily_cost_savings USING btree (date);
CREATE TABLE IF NOT EXISTS public.stats_daily_cost_savings_provider (
id character varying(36) NOT NULL,
date timestamp with time zone NOT NULL,
provider_name character varying(100) NOT NULL,
cache_read_tokens bigint DEFAULT '0'::bigint NOT NULL,
cache_read_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
cache_creation_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
estimated_full_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT stats_daily_cost_savings_provider_pkey PRIMARY KEY (id),
CONSTRAINT uq_stats_daily_cost_savings_provider UNIQUE (date, provider_name)
);
CREATE INDEX IF NOT EXISTS idx_stats_daily_cost_savings_provider_date
ON public.stats_daily_cost_savings_provider USING btree (date);
CREATE INDEX IF NOT EXISTS idx_stats_daily_cost_savings_provider_date_provider
ON public.stats_daily_cost_savings_provider USING btree (date, provider_name);
CREATE TABLE IF NOT EXISTS public.stats_daily_cost_savings_model (
id character varying(36) NOT NULL,
date timestamp with time zone NOT NULL,
model character varying(100) NOT NULL,
cache_read_tokens bigint DEFAULT '0'::bigint NOT NULL,
cache_read_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
cache_creation_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
estimated_full_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT stats_daily_cost_savings_model_pkey PRIMARY KEY (id),
CONSTRAINT uq_stats_daily_cost_savings_model UNIQUE (date, model)
);
CREATE INDEX IF NOT EXISTS idx_stats_daily_cost_savings_model_date
ON public.stats_daily_cost_savings_model USING btree (date);
CREATE INDEX IF NOT EXISTS idx_stats_daily_cost_savings_model_date_model
ON public.stats_daily_cost_savings_model USING btree (date, model);
CREATE TABLE IF NOT EXISTS public.stats_daily_cost_savings_model_provider (
id character varying(36) NOT NULL,
date timestamp with time zone NOT NULL,
model character varying(100) NOT NULL,
provider_name character varying(100) NOT NULL,
cache_read_tokens bigint DEFAULT '0'::bigint NOT NULL,
cache_read_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
cache_creation_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
estimated_full_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT stats_daily_cost_savings_model_provider_pkey PRIMARY KEY (id),
CONSTRAINT uq_stats_daily_cost_savings_model_provider UNIQUE (date, model, provider_name)
);
CREATE INDEX IF NOT EXISTS idx_stats_daily_cost_savings_model_provider_date
ON public.stats_daily_cost_savings_model_provider USING btree (date);
CREATE INDEX IF NOT EXISTS idx_stats_daily_cost_savings_model_provider_date_dims
ON public.stats_daily_cost_savings_model_provider USING btree (date, model, provider_name);
CREATE TABLE IF NOT EXISTS public.stats_user_daily_cost_savings (
id character varying(36) NOT NULL,
user_id character varying(36) NOT NULL,
username character varying(100),
date timestamp with time zone NOT NULL,
cache_read_tokens bigint DEFAULT '0'::bigint NOT NULL,
cache_read_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
cache_creation_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
estimated_full_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT stats_user_daily_cost_savings_pkey PRIMARY KEY (id),
CONSTRAINT uq_stats_user_daily_cost_savings UNIQUE (user_id, date),
CONSTRAINT stats_user_daily_cost_savings_user_id_fkey
FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_stats_user_daily_cost_savings_date
ON public.stats_user_daily_cost_savings USING btree (date);
CREATE INDEX IF NOT EXISTS idx_stats_user_daily_cost_savings_user_date
ON public.stats_user_daily_cost_savings USING btree (user_id, date);
CREATE TABLE IF NOT EXISTS public.stats_user_daily_cost_savings_provider (
id character varying(36) NOT NULL,
user_id character varying(36) NOT NULL,
username character varying(100),
date timestamp with time zone NOT NULL,
provider_name character varying(100) NOT NULL,
cache_read_tokens bigint DEFAULT '0'::bigint NOT NULL,
cache_read_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
cache_creation_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
estimated_full_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT stats_user_daily_cost_savings_provider_pkey PRIMARY KEY (id),
CONSTRAINT uq_stats_user_daily_cost_savings_provider UNIQUE (user_id, date, provider_name),
CONSTRAINT stats_user_daily_cost_savings_provider_user_id_fkey
FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_stats_user_daily_cost_savings_provider_date
ON public.stats_user_daily_cost_savings_provider USING btree (date);
CREATE INDEX IF NOT EXISTS idx_stats_user_daily_cost_savings_provider_user_date
ON public.stats_user_daily_cost_savings_provider USING btree (user_id, date);
CREATE TABLE IF NOT EXISTS public.stats_user_daily_cost_savings_model (
id character varying(36) NOT NULL,
user_id character varying(36) NOT NULL,
username character varying(100),
date timestamp with time zone NOT NULL,
model character varying(100) NOT NULL,
cache_read_tokens bigint DEFAULT '0'::bigint NOT NULL,
cache_read_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
cache_creation_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
estimated_full_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT stats_user_daily_cost_savings_model_pkey PRIMARY KEY (id),
CONSTRAINT uq_stats_user_daily_cost_savings_model UNIQUE (user_id, date, model),
CONSTRAINT stats_user_daily_cost_savings_model_user_id_fkey
FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_stats_user_daily_cost_savings_model_date
ON public.stats_user_daily_cost_savings_model USING btree (date);
CREATE INDEX IF NOT EXISTS idx_stats_user_daily_cost_savings_model_user_date
ON public.stats_user_daily_cost_savings_model USING btree (user_id, date);
CREATE TABLE IF NOT EXISTS public.stats_user_daily_cost_savings_model_provider (
id character varying(36) NOT NULL,
user_id character varying(36) NOT NULL,
username character varying(100),
date timestamp with time zone NOT NULL,
model character varying(100) NOT NULL,
provider_name character varying(100) NOT NULL,
cache_read_tokens bigint DEFAULT '0'::bigint NOT NULL,
cache_read_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
cache_creation_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
estimated_full_cost numeric(20,8) DEFAULT '0'::double precision NOT NULL,
created_at timestamp with time zone DEFAULT now() NOT NULL,
updated_at timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT stats_user_daily_cost_savings_model_provider_pkey PRIMARY KEY (id),
CONSTRAINT uq_stats_user_daily_cost_savings_model_provider
UNIQUE (user_id, date, model, provider_name),
CONSTRAINT stats_user_daily_cost_savings_model_provider_user_id_fkey
FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE
);
CREATE INDEX IF NOT EXISTS idx_stats_user_daily_cost_savings_model_provider_date
ON public.stats_user_daily_cost_savings_model_provider USING btree (date);
CREATE INDEX IF NOT EXISTS idx_stats_user_daily_cost_savings_model_provider_user_date
ON public.stats_user_daily_cost_savings_model_provider USING btree (user_id, date);

View File

@@ -0,0 +1,10 @@
001_types_and_tables.sql
002_defaults.sql
003_constraints.sql
004_indexes.sql
005_foreign_keys.sql
006_footer.sql
100_usage_capture.sql
110_redeem_codes.sql
120_stats_rollups.sql
130_stats_cost_savings.sql

View File

@@ -0,0 +1,247 @@
#!/usr/bin/env bash
set -euo pipefail
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
schema_root="${root}/schema"
driver_schema_root="${schema_root}/drivers"
bootstrap_schema_root="${schema_root}/bootstrap/postgres"
usage() {
cat <<'USAGE'
Usage:
bash crates/aether-data/schema/compose_schema.sh split
bash crates/aether-data/schema/compose_schema.sh generate
bash crates/aether-data/schema/compose_schema.sh compose
bash crates/aether-data/schema/compose_schema.sh check
split Regenerate schema source fragments from the current executable SQL.
generate Generate SQL fragments from logical schema definitions.
compose Rebuild executable SQL from schema source manifests.
check Verify generated SQL is current, bootstrap sources are readable, and executable SQL matches manifests.
USAGE
}
generate_logical_schema() {
(cd "${root}/../.." && cargo run -q -p aether-data-schema --bin aether-schema -- generate)
}
check_logical_generated() {
local args=()
local path
args+=(--require-tables-from "${root}/migrations/postgres/20260403000000_baseline.sql")
for path in "${root}/migrations/mysql/"*.sql "${root}/migrations/sqlite/"*.sql; do
[[ -f "${path}" ]] || continue
args+=(--require-tables-from "${path}")
done
(cd "${root}/../.." && cargo run -q -p aether-data-schema --bin aether-schema -- check "${args[@]}")
printf 'ok generated logical schema\n'
}
manifest_path() {
local target="$1"
printf '%s/manifest.txt' "$(source_dir_path "${target}")"
}
source_dir_path() {
local target="$1"
printf '%s/%s' "${driver_schema_root}" "${target}"
}
output_path() {
local target="$1"
case "${target}" in
postgres/baseline)
printf '%s/migrations/postgres/20260403000000_baseline.sql' "${root}"
;;
mysql/baseline)
printf '%s/migrations/mysql/20260403000000_baseline.sql' "${root}"
;;
sqlite/baseline)
printf '%s/migrations/sqlite/20260403000000_baseline.sql' "${root}"
;;
*)
printf 'unknown schema target: %s\n' "${target}" >&2
exit 2
;;
esac
}
write_manifest() {
local target="$1"
shift
local manifest
manifest="$(manifest_path "${target}")"
mkdir -p "$(dirname "${manifest}")"
: > "${manifest}"
local part
for part in "$@"; do
printf '%s\n' "${part}" >> "${manifest}"
done
}
append_manifest() {
local target="$1"
shift
local manifest
manifest="$(manifest_path "${target}")"
local part
for part in "$@"; do
printf '%s\n' "${part}" >> "${manifest}"
done
}
split_fragment() {
local source="$1"
local target="$2"
local filename="$3"
local start_line="$4"
local end_line="$5"
local output
output="$(source_dir_path "${target}")/${filename}"
mkdir -p "$(dirname "${output}")"
if [[ "${end_line}" == "EOF" ]]; then
sed -n "${start_line},\$p" "${source}" > "${output}"
else
sed -n "${start_line},${end_line}p" "${source}" > "${output}"
fi
printf '%s: lines %s-%s\n' "${output#${root}/}" "${start_line}" "${end_line}"
}
compose_target_to_stdout() {
local target="$1"
local manifest
manifest="$(manifest_path "${target}")"
if [[ ! -f "${manifest}" ]]; then
printf 'missing schema manifest: %s\n' "${manifest}" >&2
exit 2
fi
local part
while IFS= read -r part || [[ -n "${part}" ]]; do
[[ -z "${part}" || "${part}" == \#* ]] && continue
cat "$(source_dir_path "${target}")/${part}"
done < "${manifest}"
}
compose_target() {
local target="$1"
local output
output="$(output_path "${target}")"
compose_target_to_stdout "${target}" > "${output}"
printf 'composed %s from %s\n' "${output#${root}/}" "$(manifest_path "${target}")"
}
check_target() {
local target="$1"
local output tmp
output="$(output_path "${target}")"
tmp="$(mktemp)"
compose_target_to_stdout "${target}" > "${tmp}"
if ! diff -u "${output}" "${tmp}"; then
rm -f "${tmp}"
printf 'schema source does not match %s\n' "${output#${root}/}" >&2
exit 1
fi
rm -f "${tmp}"
printf 'ok %s\n' "${target}"
}
split_postgres_baseline() {
local source="${root}/migrations/postgres/20260403000000_baseline.sql"
local target="postgres/baseline"
write_manifest "${target}" \
"001_types_and_tables.sql" \
"002_defaults.sql" \
"003_constraints.sql" \
"004_indexes.sql" \
"005_foreign_keys.sql" \
"006_footer.sql"
split_fragment "${source}" "${target}" 001_types_and_tables.sql 1 1349
split_fragment "${source}" "${target}" 002_defaults.sql 1350 1365
split_fragment "${source}" "${target}" 003_constraints.sql 1366 2490
split_fragment "${source}" "${target}" 004_indexes.sql 2491 3730
split_fragment "${source}" "${target}" 005_foreign_keys.sql 3731 4582
split_fragment "${source}" "${target}" 006_footer.sql 4583 EOF
}
check_bootstrap_sources() {
local manifest="${bootstrap_schema_root}/manifest.txt"
local tmp
tmp="$(mktemp)"
local part
while IFS= read -r part || [[ -n "${part}" ]]; do
[[ -z "${part}" || "${part}" == \#* ]] && continue
cat "${bootstrap_schema_root}/${part}" >> "${tmp}"
done < "${manifest}"
rm -f "${tmp}"
printf 'ok bootstrap/postgres source\n'
}
split_linear_baseline() {
local driver="$1"
local source="${root}/migrations/${driver}/20260403000000_baseline.sql"
local target="${driver}/baseline"
write_manifest "${target}" \
"001_identity.sql" \
"002_provider_catalog.sql" \
"003_auth_config.sql" \
"004_proxy_nodes.sql" \
"005_wallet_billing.sql" \
"006_usage.sql"
if [[ "${driver}" == "mysql" ]]; then
split_fragment "${source}" "${target}" 001_identity.sql 1 121
split_fragment "${source}" "${target}" 002_provider_catalog.sql 122 417
split_fragment "${source}" "${target}" 003_auth_config.sql 418 487
split_fragment "${source}" "${target}" 004_proxy_nodes.sql 488 527
split_fragment "${source}" "${target}" 005_wallet_billing.sql 528 711
split_fragment "${source}" "${target}" 006_usage.sql 712 EOF
else
split_fragment "${source}" "${target}" 001_identity.sql 1 117
split_fragment "${source}" "${target}" 002_provider_catalog.sql 118 417
split_fragment "${source}" "${target}" 003_auth_config.sql 418 485
split_fragment "${source}" "${target}" 004_proxy_nodes.sql 486 525
split_fragment "${source}" "${target}" 005_wallet_billing.sql 526 728
split_fragment "${source}" "${target}" 006_usage.sql 729 EOF
fi
}
targets=(
"postgres/baseline"
"mysql/baseline"
"sqlite/baseline"
)
cmd="${1:-}"
case "${cmd}" in
split)
split_postgres_baseline
split_linear_baseline mysql
split_linear_baseline sqlite
;;
generate)
generate_logical_schema
;;
compose)
for target in "${targets[@]}"; do
compose_target "${target}"
done
;;
check)
check_logical_generated
check_bootstrap_sources
for target in "${targets[@]}"; do
check_target "${target}"
done
;;
-h|--help|help|"")
usage
;;
*)
usage >&2
exit 2
;;
esac

View File

@@ -0,0 +1,120 @@
CREATE TABLE IF NOT EXISTS users (
id VARCHAR(64) PRIMARY KEY,
external_id VARCHAR(255),
email VARCHAR(320),
username VARCHAR(255),
password_hash VARCHAR(255),
role VARCHAR(64),
auth_source VARCHAR(64) NOT NULL DEFAULT 'local',
email_verified TINYINT(1) NOT NULL DEFAULT 0,
is_active TINYINT(1) NOT NULL DEFAULT 1,
is_deleted TINYINT(1) NOT NULL DEFAULT 0,
allowed_models TEXT,
allowed_providers TEXT,
allowed_api_formats TEXT,
model_capability_settings TEXT,
rate_limit INT,
metadata TEXT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
last_login_at BIGINT,
UNIQUE KEY users_email_key (email),
UNIQUE KEY users_username_key (username)
);
CREATE TABLE IF NOT EXISTS api_keys (
id VARCHAR(64) PRIMARY KEY,
user_id VARCHAR(64) NOT NULL,
key_hash VARCHAR(255) NOT NULL,
key_encrypted TEXT,
name VARCHAR(255),
key_prefix VARCHAR(64),
status VARCHAR(64) NOT NULL DEFAULT 'active',
allowed_models TEXT,
allowed_providers TEXT,
allowed_api_formats TEXT,
rate_limit INT DEFAULT 100,
concurrent_limit INT,
force_capabilities TEXT,
is_active TINYINT(1) NOT NULL DEFAULT 1,
is_locked TINYINT(1) NOT NULL DEFAULT 0,
is_standalone TINYINT(1) NOT NULL DEFAULT 0,
auto_delete_on_expiry TINYINT(1) NOT NULL DEFAULT 0,
total_requests BIGINT NOT NULL DEFAULT 0,
total_tokens BIGINT NOT NULL DEFAULT 0,
total_cost_usd DOUBLE NOT NULL DEFAULT 0,
metadata TEXT,
expires_at BIGINT,
last_used_at BIGINT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY api_keys_key_hash_key (key_hash),
KEY api_keys_user_id_idx (user_id)
);
CREATE TABLE IF NOT EXISTS audit_logs (
id VARCHAR(64) PRIMARY KEY,
event_type VARCHAR(64) NOT NULL,
user_id VARCHAR(64),
api_key_id VARCHAR(64),
description TEXT NOT NULL,
ip_address VARCHAR(64),
user_agent VARCHAR(512),
request_id VARCHAR(128),
event_metadata TEXT,
status_code INT,
error_message TEXT,
created_at BIGINT NOT NULL,
KEY audit_logs_created_at_idx (created_at),
KEY audit_logs_event_type_idx (event_type),
KEY audit_logs_request_id_idx (request_id),
KEY audit_logs_user_id_idx (user_id)
);
CREATE TABLE IF NOT EXISTS announcements (
id VARCHAR(64) PRIMARY KEY,
title VARCHAR(200) NOT NULL,
content TEXT NOT NULL,
`type` VARCHAR(32) NOT NULL DEFAULT 'info',
priority INT NOT NULL DEFAULT 0,
author_id VARCHAR(64),
is_active TINYINT(1) NOT NULL DEFAULT 1,
is_pinned TINYINT(1) NOT NULL DEFAULT 0,
start_time BIGINT,
end_time BIGINT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY announcements_author_id_idx (author_id),
KEY announcements_created_at_idx (created_at),
KEY announcements_is_active_idx (is_active)
);
CREATE TABLE IF NOT EXISTS announcement_reads (
id VARCHAR(64) PRIMARY KEY,
user_id VARCHAR(64) NOT NULL,
announcement_id VARCHAR(64) NOT NULL,
read_at BIGINT NOT NULL,
UNIQUE KEY uq_user_announcement (user_id, announcement_id),
KEY announcement_reads_announcement_id_idx (announcement_id),
KEY announcement_reads_user_id_idx (user_id)
);
CREATE TABLE IF NOT EXISTS management_tokens (
id VARCHAR(64) PRIMARY KEY,
user_id VARCHAR(64) NOT NULL,
name VARCHAR(255) NOT NULL,
description TEXT,
token_hash VARCHAR(255) NOT NULL,
token_prefix VARCHAR(64),
allowed_ips TEXT,
expires_at BIGINT,
last_used_at BIGINT,
last_used_ip VARCHAR(255),
usage_count BIGINT NOT NULL DEFAULT 0,
is_active TINYINT(1) NOT NULL DEFAULT 1,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY management_tokens_token_hash_key (token_hash),
UNIQUE KEY uq_management_tokens_user_name (user_id, name),
KEY management_tokens_user_id_idx (user_id)
);

View File

@@ -0,0 +1,295 @@
CREATE TABLE IF NOT EXISTS billing_rules (
id VARCHAR(64) PRIMARY KEY,
global_model_id VARCHAR(64),
model_id VARCHAR(64),
name VARCHAR(255) NOT NULL,
task_type VARCHAR(64) NOT NULL DEFAULT 'chat',
expression TEXT NOT NULL,
variables TEXT NOT NULL,
dimension_mappings TEXT NOT NULL,
is_enabled TINYINT(1) NOT NULL DEFAULT 1,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY billing_rules_global_model_task_idx (global_model_id, task_type, is_enabled),
KEY billing_rules_model_task_idx (model_id, task_type, is_enabled)
);
CREATE TABLE IF NOT EXISTS dimension_collectors (
id VARCHAR(64) PRIMARY KEY,
api_format VARCHAR(64) NOT NULL,
task_type VARCHAR(64) NOT NULL,
dimension_name VARCHAR(128) NOT NULL,
source_type VARCHAR(64) NOT NULL,
source_path VARCHAR(255),
value_type VARCHAR(64) NOT NULL DEFAULT 'float',
transform_expression TEXT,
default_value VARCHAR(255),
priority INT NOT NULL DEFAULT 0,
is_enabled TINYINT(1) NOT NULL DEFAULT 1,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY dimension_collectors_enabled_idx (
api_format,
task_type,
dimension_name,
priority,
is_enabled
)
);
CREATE TABLE IF NOT EXISTS providers (
id VARCHAR(64) PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT,
website VARCHAR(500),
provider_type VARCHAR(64) NOT NULL,
billing_type VARCHAR(64),
monthly_quota_usd DOUBLE,
monthly_used_usd DOUBLE,
quota_reset_day INT,
quota_last_reset_at BIGINT,
quota_expires_at BIGINT,
enabled TINYINT(1) NOT NULL DEFAULT 1,
is_active TINYINT(1) NOT NULL DEFAULT 1,
priority BIGINT NOT NULL DEFAULT 0,
provider_priority INT NOT NULL DEFAULT 100,
keep_priority_on_conversion TINYINT(1) NOT NULL DEFAULT 0,
enable_format_conversion TINYINT(1) NOT NULL DEFAULT 1,
concurrent_limit INT,
max_retries INT,
proxy TEXT,
request_timeout DOUBLE,
stream_first_byte_timeout DOUBLE,
config TEXT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY providers_name_key (name)
);
CREATE TABLE IF NOT EXISTS provider_api_keys (
id VARCHAR(64) PRIMARY KEY,
provider_id VARCHAR(64) NOT NULL,
name VARCHAR(255) NOT NULL,
api_key TEXT,
encrypted_key TEXT,
auth_type VARCHAR(32) NOT NULL DEFAULT 'api_key',
auth_config TEXT,
note TEXT,
internal_priority INT NOT NULL DEFAULT 50,
capabilities TEXT,
api_formats TEXT,
auth_type_by_format TEXT,
allow_auth_channel_mismatch_formats TEXT,
rate_multipliers TEXT,
global_priority_by_format TEXT,
allowed_models TEXT,
expires_at BIGINT,
cache_ttl_minutes INT NOT NULL DEFAULT 5,
max_probe_interval_minutes INT NOT NULL DEFAULT 32,
proxy TEXT,
fingerprint TEXT,
concurrent_limit INT,
learned_rpm_limit INT,
concurrent_429_count INT NOT NULL DEFAULT 0,
rpm_429_count INT NOT NULL DEFAULT 0,
last_429_at BIGINT,
last_429_type VARCHAR(64),
adjustment_history TEXT,
utilization_samples TEXT,
last_probe_increase_at BIGINT,
last_rpm_peak INT,
request_count BIGINT NOT NULL DEFAULT 0,
total_tokens BIGINT NOT NULL DEFAULT 0,
total_cost_usd DOUBLE NOT NULL DEFAULT 0,
success_count BIGINT NOT NULL DEFAULT 0,
error_count BIGINT NOT NULL DEFAULT 0,
total_response_time_ms BIGINT NOT NULL DEFAULT 0,
last_used_at BIGINT,
auto_fetch_models TINYINT(1) NOT NULL DEFAULT 0,
last_models_fetch_at BIGINT,
last_models_fetch_error TEXT,
locked_models TEXT,
model_include_patterns TEXT,
model_exclude_patterns TEXT,
upstream_metadata TEXT,
oauth_invalid_at BIGINT,
oauth_invalid_reason VARCHAR(255),
status_snapshot TEXT,
health_by_format TEXT,
circuit_breaker_by_format TEXT,
status VARCHAR(64) NOT NULL DEFAULT 'active',
is_active TINYINT(1) NOT NULL DEFAULT 1,
weight BIGINT NOT NULL DEFAULT 1,
rpm_limit BIGINT,
metadata TEXT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY provider_api_keys_provider_id_idx (provider_id)
);
CREATE TABLE IF NOT EXISTS gemini_file_mappings (
id VARCHAR(64) PRIMARY KEY,
file_name VARCHAR(512) NOT NULL,
key_id VARCHAR(64) NOT NULL,
user_id VARCHAR(64),
display_name VARCHAR(512),
mime_type VARCHAR(255),
source_hash VARCHAR(128),
created_at BIGINT NOT NULL,
expires_at BIGINT NOT NULL,
UNIQUE KEY gemini_file_mappings_file_name_key (file_name),
KEY gemini_file_mappings_key_id_idx (key_id),
KEY gemini_file_mappings_user_id_idx (user_id),
KEY gemini_file_mappings_expires_at_idx (expires_at),
KEY gemini_file_mappings_source_hash_idx (source_hash)
);
CREATE TABLE IF NOT EXISTS request_candidates (
id VARCHAR(64) PRIMARY KEY,
request_id VARCHAR(128) NOT NULL,
user_id VARCHAR(64),
api_key_id VARCHAR(64),
username VARCHAR(255),
api_key_name VARCHAR(255),
candidate_index INT NOT NULL,
retry_index INT NOT NULL DEFAULT 0,
provider_id VARCHAR(64),
endpoint_id VARCHAR(64),
key_id VARCHAR(64),
status VARCHAR(32) NOT NULL,
skip_reason TEXT,
is_cached TINYINT(1) NOT NULL DEFAULT 0,
status_code INT,
error_type VARCHAR(128),
error_message TEXT,
latency_ms INT,
concurrent_requests INT,
extra_data TEXT,
required_capabilities TEXT,
created_at BIGINT NOT NULL,
started_at BIGINT,
finished_at BIGINT,
UNIQUE KEY uq_request_candidate_with_retry (request_id, candidate_index, retry_index),
KEY request_candidates_request_id_idx (request_id),
KEY request_candidates_provider_id_idx (provider_id),
KEY request_candidates_endpoint_id_idx (endpoint_id),
KEY request_candidates_status_idx (status),
KEY request_candidates_created_at_idx (created_at),
KEY request_candidates_endpoint_status_created_idx (endpoint_id, status, created_at)
);
CREATE TABLE IF NOT EXISTS video_tasks (
id VARCHAR(64) PRIMARY KEY,
short_id VARCHAR(32),
request_id VARCHAR(128) NOT NULL,
user_id VARCHAR(64),
api_key_id VARCHAR(64),
username VARCHAR(255),
api_key_name VARCHAR(255),
external_task_id VARCHAR(255),
provider_id VARCHAR(64),
endpoint_id VARCHAR(64),
key_id VARCHAR(64),
client_api_format VARCHAR(128),
provider_api_format VARCHAR(128),
format_converted TINYINT(1) NOT NULL DEFAULT 0,
model VARCHAR(255),
prompt TEXT,
original_request_body TEXT,
duration_seconds INT,
resolution VARCHAR(64),
aspect_ratio VARCHAR(32),
size VARCHAR(64),
status VARCHAR(32) NOT NULL DEFAULT 'pending',
progress_percent INT NOT NULL DEFAULT 0,
progress_message TEXT,
retry_count INT NOT NULL DEFAULT 0,
poll_interval_seconds INT NOT NULL DEFAULT 10,
next_poll_at BIGINT,
poll_count INT NOT NULL DEFAULT 0,
max_poll_count INT NOT NULL DEFAULT 360,
created_at BIGINT NOT NULL,
submitted_at BIGINT,
completed_at BIGINT,
updated_at BIGINT NOT NULL,
error_code VARCHAR(128),
error_message TEXT,
video_url TEXT,
request_metadata TEXT,
UNIQUE KEY video_tasks_short_id_key (short_id),
UNIQUE KEY video_tasks_request_id_key (request_id),
KEY video_tasks_external_id_idx (external_task_id),
KEY video_tasks_next_poll_idx (next_poll_at),
KEY video_tasks_user_status_idx (user_id, status),
KEY video_tasks_api_key_id_idx (api_key_id),
KEY video_tasks_provider_id_idx (provider_id),
KEY video_tasks_endpoint_id_idx (endpoint_id),
KEY video_tasks_key_id_idx (key_id)
);
CREATE TABLE IF NOT EXISTS provider_endpoints (
id VARCHAR(64) PRIMARY KEY,
provider_id VARCHAR(64) NOT NULL,
name VARCHAR(255) NOT NULL,
base_url TEXT NOT NULL,
api_format VARCHAR(128),
api_family VARCHAR(128),
endpoint_kind VARCHAR(128),
enabled TINYINT(1) NOT NULL DEFAULT 1,
is_active TINYINT(1) NOT NULL DEFAULT 1,
health_score DOUBLE NOT NULL DEFAULT 1.0,
weight BIGINT NOT NULL DEFAULT 1,
header_rules TEXT,
body_rules TEXT,
max_retries INT,
custom_path TEXT,
metadata TEXT,
config TEXT,
format_acceptance_config TEXT,
proxy TEXT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY provider_endpoints_provider_id_idx (provider_id)
);
CREATE TABLE IF NOT EXISTS models (
id VARCHAR(64) PRIMARY KEY,
provider_id VARCHAR(64) NOT NULL,
global_model_id VARCHAR(64),
provider_model_name VARCHAR(255) NOT NULL,
global_model_name VARCHAR(255),
api_format VARCHAR(128),
enabled TINYINT(1) NOT NULL DEFAULT 1,
is_active TINYINT(1) NOT NULL DEFAULT 1,
is_available TINYINT(1) NOT NULL DEFAULT 1,
price_per_request DOUBLE,
tiered_pricing TEXT,
supports_vision TINYINT(1),
supports_function_calling TINYINT(1),
supports_streaming TINYINT(1),
supports_extended_thinking TINYINT(1),
supports_image_generation TINYINT(1),
provider_model_mappings TEXT,
config TEXT,
metadata TEXT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY models_provider_id_idx (provider_id)
);
CREATE TABLE IF NOT EXISTS global_models (
id VARCHAR(64) PRIMARY KEY,
name VARCHAR(255) NOT NULL,
display_name VARCHAR(255),
enabled TINYINT(1) NOT NULL DEFAULT 1,
is_active TINYINT(1) NOT NULL DEFAULT 1,
default_price_per_request DOUBLE,
default_tiered_pricing TEXT,
supported_capabilities TEXT,
usage_count BIGINT NOT NULL DEFAULT 0,
config TEXT,
metadata TEXT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY global_models_name_key (name)
);

View File

@@ -0,0 +1,69 @@
CREATE TABLE IF NOT EXISTS system_configs (
id VARCHAR(64) PRIMARY KEY,
`key` VARCHAR(255) NOT NULL,
value TEXT NOT NULL,
description TEXT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY system_configs_key_key (`key`)
);
CREATE TABLE IF NOT EXISTS auth_modules (
id VARCHAR(64) PRIMARY KEY,
module_type VARCHAR(128) NOT NULL,
enabled TINYINT(1) NOT NULL DEFAULT 1,
config TEXT NOT NULL,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY auth_modules_module_type_key (module_type)
);
CREATE TABLE IF NOT EXISTS oauth_providers (
provider_type VARCHAR(64) PRIMARY KEY,
display_name VARCHAR(255) NOT NULL,
client_id TEXT NOT NULL,
client_secret_encrypted TEXT,
authorization_url_override VARCHAR(500),
token_url_override VARCHAR(500),
userinfo_url_override VARCHAR(500),
scopes TEXT,
redirect_uri VARCHAR(500) NOT NULL,
frontend_callback_url VARCHAR(500) NOT NULL,
attribute_mapping TEXT,
extra_config TEXT,
is_enabled TINYINT(1) NOT NULL DEFAULT 0,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL
);
CREATE TABLE IF NOT EXISTS ldap_configs (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
server_url VARCHAR(255) NOT NULL,
bind_dn TEXT NOT NULL,
bind_password_encrypted TEXT,
base_dn TEXT NOT NULL,
user_search_filter TEXT NOT NULL DEFAULT '(uid={username})',
username_attr VARCHAR(50) NOT NULL DEFAULT 'uid',
email_attr VARCHAR(50) NOT NULL DEFAULT 'mail',
display_name_attr VARCHAR(50) NOT NULL DEFAULT 'cn',
is_enabled TINYINT(1) NOT NULL DEFAULT 0,
is_exclusive TINYINT(1) NOT NULL DEFAULT 0,
use_starttls TINYINT(1) NOT NULL DEFAULT 0,
connect_timeout INT NOT NULL DEFAULT 10,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL
);
CREATE TABLE IF NOT EXISTS user_oauth_links (
id VARCHAR(64) PRIMARY KEY,
user_id VARCHAR(64) NOT NULL,
provider_type VARCHAR(64) NOT NULL,
provider_user_id VARCHAR(255) NOT NULL,
provider_username VARCHAR(255),
provider_email VARCHAR(255),
extra_data TEXT,
linked_at BIGINT NOT NULL,
last_login_at BIGINT,
KEY user_oauth_links_provider_type_idx (provider_type),
KEY user_oauth_links_user_id_idx (user_id)
);

View File

@@ -0,0 +1,39 @@
CREATE TABLE IF NOT EXISTS proxy_nodes (
id VARCHAR(64) PRIMARY KEY,
name VARCHAR(255) NOT NULL,
ip VARCHAR(512) NOT NULL,
port INT NOT NULL,
region VARCHAR(100),
status VARCHAR(32) NOT NULL DEFAULT 'online',
registered_by VARCHAR(64),
last_heartbeat_at BIGINT,
heartbeat_interval INT NOT NULL DEFAULT 30,
active_connections INT NOT NULL DEFAULT 0,
total_requests BIGINT NOT NULL DEFAULT 0,
avg_latency_ms DOUBLE,
is_manual TINYINT(1) NOT NULL DEFAULT 0,
proxy_url VARCHAR(500),
proxy_username VARCHAR(255),
proxy_password VARCHAR(500),
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
remote_config TEXT,
config_version INT NOT NULL DEFAULT 0,
hardware_info TEXT,
estimated_max_concurrency INT,
tunnel_mode TINYINT(1) NOT NULL DEFAULT 0,
tunnel_connected TINYINT(1) NOT NULL DEFAULT 0,
tunnel_connected_at BIGINT,
failed_requests BIGINT NOT NULL DEFAULT 0,
dns_failures BIGINT NOT NULL DEFAULT 0,
stream_errors BIGINT NOT NULL DEFAULT 0,
proxy_metadata TEXT
);
CREATE TABLE IF NOT EXISTS proxy_node_events (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
node_id VARCHAR(64) NOT NULL,
event_type VARCHAR(64) NOT NULL,
detail VARCHAR(500),
created_at BIGINT NOT NULL
);

View File

@@ -0,0 +1,183 @@
CREATE TABLE IF NOT EXISTS wallets (
id VARCHAR(64) PRIMARY KEY,
user_id VARCHAR(64),
api_key_id VARCHAR(64),
balance DOUBLE NOT NULL DEFAULT 0,
gift_balance DOUBLE NOT NULL DEFAULT 0,
limit_mode VARCHAR(64) NOT NULL DEFAULT 'finite',
currency VARCHAR(16) NOT NULL DEFAULT 'USD',
status VARCHAR(64) NOT NULL DEFAULT 'active',
total_recharged DOUBLE NOT NULL DEFAULT 0,
total_consumed DOUBLE NOT NULL DEFAULT 0,
total_refunded DOUBLE NOT NULL DEFAULT 0,
total_adjusted DOUBLE NOT NULL DEFAULT 0,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY wallets_user_id_key (user_id),
UNIQUE KEY wallets_api_key_id_key (api_key_id),
KEY wallets_api_key_id_idx (api_key_id),
KEY wallets_user_id_idx (user_id)
);
CREATE TABLE IF NOT EXISTS wallet_transactions (
id VARCHAR(64) PRIMARY KEY,
wallet_id VARCHAR(64) NOT NULL,
category VARCHAR(64) NOT NULL,
reason_code VARCHAR(64) NOT NULL,
amount DOUBLE NOT NULL,
balance_before DOUBLE NOT NULL,
balance_after DOUBLE NOT NULL,
recharge_balance_before DOUBLE NOT NULL,
recharge_balance_after DOUBLE NOT NULL,
gift_balance_before DOUBLE NOT NULL,
gift_balance_after DOUBLE NOT NULL,
link_type VARCHAR(64),
link_id VARCHAR(128),
operator_id VARCHAR(64),
description TEXT,
created_at BIGINT NOT NULL,
KEY idx_wallet_tx_wallet_created (wallet_id, created_at),
KEY idx_wallet_tx_category_created (category, created_at),
KEY idx_wallet_tx_reason_created (reason_code, created_at),
KEY idx_wallet_tx_link (link_type, link_id),
KEY ix_wallet_transactions_operator_id (operator_id)
);
CREATE TABLE IF NOT EXISTS wallet_daily_usage_ledgers (
id VARCHAR(64) PRIMARY KEY,
wallet_id VARCHAR(64) NOT NULL,
billing_date VARCHAR(16) NOT NULL,
billing_timezone VARCHAR(64) NOT NULL,
total_cost_usd DOUBLE NOT NULL DEFAULT 0,
total_requests BIGINT NOT NULL DEFAULT 0,
input_tokens BIGINT NOT NULL DEFAULT 0,
output_tokens BIGINT NOT NULL DEFAULT 0,
cache_creation_tokens BIGINT NOT NULL DEFAULT 0,
cache_read_tokens BIGINT NOT NULL DEFAULT 0,
first_finalized_at BIGINT,
last_finalized_at BIGINT,
aggregated_at BIGINT NOT NULL,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY idx_wallet_daily_usage_wallet_date (wallet_id, billing_timezone, billing_date)
);
CREATE TABLE IF NOT EXISTS payment_orders (
id VARCHAR(64) PRIMARY KEY,
order_no VARCHAR(128) NOT NULL,
wallet_id VARCHAR(64) NOT NULL,
user_id VARCHAR(64),
amount_usd DOUBLE NOT NULL,
pay_amount DOUBLE,
pay_currency VARCHAR(16),
exchange_rate DOUBLE,
refunded_amount_usd DOUBLE NOT NULL DEFAULT 0,
refundable_amount_usd DOUBLE NOT NULL DEFAULT 0,
payment_method VARCHAR(64) NOT NULL,
gateway_order_id VARCHAR(128),
gateway_response TEXT,
status VARCHAR(64) NOT NULL DEFAULT 'pending',
created_at BIGINT NOT NULL,
paid_at BIGINT,
credited_at BIGINT,
expires_at BIGINT,
UNIQUE KEY uq_payment_orders_order_no (order_no),
KEY idx_payment_orders_wallet_created (wallet_id, created_at),
KEY idx_payment_orders_user_created (user_id, created_at),
KEY idx_payment_orders_status (status),
KEY idx_payment_orders_gateway_order_id (gateway_order_id)
);
CREATE TABLE IF NOT EXISTS payment_callbacks (
id VARCHAR(64) PRIMARY KEY,
payment_order_id VARCHAR(64),
payment_method VARCHAR(64) NOT NULL,
callback_key VARCHAR(128) NOT NULL,
order_no VARCHAR(128),
gateway_order_id VARCHAR(128),
payload_hash VARCHAR(128),
signature_valid TINYINT(1) NOT NULL DEFAULT 0,
status VARCHAR(64) NOT NULL DEFAULT 'received',
payload TEXT,
error_message TEXT,
created_at BIGINT NOT NULL,
processed_at BIGINT,
UNIQUE KEY uq_payment_callbacks_callback_key (callback_key),
KEY idx_payment_callbacks_order (order_no),
KEY idx_payment_callbacks_gateway_order (gateway_order_id),
KEY idx_payment_callbacks_created (created_at),
KEY ix_payment_callbacks_payment_order_id (payment_order_id)
);
CREATE TABLE IF NOT EXISTS refund_requests (
id VARCHAR(64) PRIMARY KEY,
refund_no VARCHAR(128) NOT NULL,
wallet_id VARCHAR(64) NOT NULL,
user_id VARCHAR(64),
payment_order_id VARCHAR(64),
source_type VARCHAR(64) NOT NULL,
source_id VARCHAR(128),
refund_mode VARCHAR(64) NOT NULL,
amount_usd DOUBLE NOT NULL,
status VARCHAR(64) NOT NULL DEFAULT 'pending_approval',
reason TEXT,
requested_by VARCHAR(64),
approved_by VARCHAR(64),
processed_by VARCHAR(64),
gateway_refund_id VARCHAR(128),
payout_method VARCHAR(64),
payout_reference VARCHAR(255),
payout_proof TEXT,
failure_reason TEXT,
idempotency_key VARCHAR(128),
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
processed_at BIGINT,
completed_at BIGINT,
UNIQUE KEY uq_refund_requests_refund_no (refund_no),
UNIQUE KEY uq_refund_requests_idempotency_key (idempotency_key),
KEY idx_refund_wallet_created (wallet_id, created_at),
KEY idx_refund_user_created (user_id, created_at),
KEY idx_refund_status (status),
KEY ix_refund_requests_payment_order_id (payment_order_id),
KEY ix_refund_requests_requested_by (requested_by),
KEY ix_refund_requests_approved_by (approved_by),
KEY ix_refund_requests_processed_by (processed_by)
);
CREATE TABLE IF NOT EXISTS redeem_code_batches (
id VARCHAR(64) PRIMARY KEY,
name VARCHAR(255) NOT NULL,
amount_usd DOUBLE NOT NULL,
currency VARCHAR(16) NOT NULL DEFAULT 'USD',
balance_bucket VARCHAR(64) NOT NULL DEFAULT 'gift',
total_count INT NOT NULL,
status VARCHAR(64) NOT NULL DEFAULT 'active',
description TEXT,
created_by VARCHAR(64),
expires_at BIGINT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY idx_redeem_code_batches_status (status, created_at)
);
CREATE TABLE IF NOT EXISTS redeem_codes (
id VARCHAR(64) PRIMARY KEY,
batch_id VARCHAR(64) NOT NULL,
code_hash VARCHAR(128) NOT NULL,
code_prefix VARCHAR(16) NOT NULL,
code_suffix VARCHAR(16) NOT NULL,
status VARCHAR(64) NOT NULL DEFAULT 'active',
redeemed_by_user_id VARCHAR(64),
redeemed_wallet_id VARCHAR(64),
redeemed_payment_order_id VARCHAR(64),
redeemed_at BIGINT,
disabled_by VARCHAR(64),
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
UNIQUE KEY uq_redeem_codes_code_hash (code_hash),
KEY idx_redeem_codes_batch_created (batch_id, created_at),
KEY idx_redeem_codes_status (status, updated_at),
KEY idx_redeem_codes_redeemed_user (redeemed_by_user_id, redeemed_at),
KEY idx_redeem_codes_redeemed_order (redeemed_payment_order_id)
);

View File

@@ -0,0 +1,85 @@
CREATE TABLE IF NOT EXISTS `usage` (
request_id VARCHAR(128) PRIMARY KEY,
id VARCHAR(128),
user_id VARCHAR(64),
api_key_id VARCHAR(64),
provider_name VARCHAR(255) NOT NULL DEFAULT 'unknown',
model VARCHAR(255) NOT NULL DEFAULT 'unknown',
target_model VARCHAR(255),
provider_id VARCHAR(64),
provider_endpoint_id VARCHAR(64),
provider_api_key_id VARCHAR(64),
request_type VARCHAR(64),
api_format VARCHAR(64),
api_family VARCHAR(64),
endpoint_kind VARCHAR(64),
endpoint_api_format VARCHAR(64),
provider_api_family VARCHAR(64),
provider_endpoint_kind VARCHAR(64),
has_format_conversion TINYINT(1) NOT NULL DEFAULT 0,
is_stream TINYINT(1) NOT NULL DEFAULT 0,
input_tokens BIGINT NOT NULL DEFAULT 0,
output_tokens BIGINT NOT NULL DEFAULT 0,
total_tokens BIGINT NOT NULL DEFAULT 0,
cache_creation_input_tokens BIGINT NOT NULL DEFAULT 0,
cache_creation_ephemeral_5m_input_tokens BIGINT NOT NULL DEFAULT 0,
cache_creation_ephemeral_1h_input_tokens BIGINT NOT NULL DEFAULT 0,
cache_read_input_tokens BIGINT NOT NULL DEFAULT 0,
cache_creation_cost_usd DOUBLE NOT NULL DEFAULT 0,
cache_read_cost_usd DOUBLE NOT NULL DEFAULT 0,
output_price_per_1m DOUBLE,
status_code INT,
error_message TEXT,
error_category VARCHAR(255),
response_time_ms BIGINT,
first_byte_time_ms BIGINT,
wallet_id VARCHAR(64),
status VARCHAR(64) NOT NULL DEFAULT 'completed',
billing_status VARCHAR(64) NOT NULL DEFAULT 'pending',
total_cost_usd DOUBLE NOT NULL DEFAULT 0,
actual_total_cost_usd DOUBLE NOT NULL DEFAULT 0,
request_metadata TEXT,
candidate_id VARCHAR(128),
candidate_index BIGINT,
key_name VARCHAR(255),
planner_kind VARCHAR(64),
route_family VARCHAR(128),
route_kind VARCHAR(128),
execution_path VARCHAR(128),
local_execution_runtime_miss_reason VARCHAR(255),
wallet_balance_before DOUBLE,
wallet_balance_after DOUBLE,
wallet_recharge_balance_before DOUBLE,
wallet_recharge_balance_after DOUBLE,
wallet_gift_balance_before DOUBLE,
wallet_gift_balance_after DOUBLE,
finalized_at BIGINT,
created_at_unix_ms BIGINT NOT NULL DEFAULT 0,
updated_at_unix_secs BIGINT NOT NULL DEFAULT 0,
KEY usage_api_key_id_idx (api_key_id),
KEY usage_billing_status_idx (billing_status),
KEY usage_created_at_idx (created_at_unix_ms),
KEY usage_provider_api_key_id_idx (provider_api_key_id),
KEY usage_provider_id_idx (provider_id),
KEY usage_request_id_idx (request_id),
KEY usage_user_id_idx (user_id),
KEY usage_wallet_id_idx (wallet_id)
);
CREATE TABLE IF NOT EXISTS usage_settlement_snapshots (
request_id VARCHAR(128) PRIMARY KEY,
billing_status VARCHAR(64) NOT NULL,
wallet_id VARCHAR(64),
wallet_balance_before DOUBLE,
wallet_balance_after DOUBLE,
wallet_recharge_balance_before DOUBLE,
wallet_recharge_balance_after DOUBLE,
wallet_gift_balance_before DOUBLE,
wallet_gift_balance_after DOUBLE,
provider_monthly_used_usd DOUBLE,
finalized_at BIGINT,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL,
KEY usage_settlement_snapshots_billing_status_idx (billing_status),
KEY usage_settlement_snapshots_wallet_id_idx (wallet_id)
);

View File

@@ -0,0 +1,6 @@
001_identity.sql
002_provider_catalog.sql
003_auth_config.sql
004_proxy_nodes.sql
005_wallet_billing.sql
006_usage.sql

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
-- Name: ldap_configs id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.ldap_configs ALTER COLUMN id SET DEFAULT nextval('public.ldap_configs_id_seq'::regclass);
--
-- Name: proxy_node_events id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.proxy_node_events ALTER COLUMN id SET DEFAULT nextval('public.proxy_node_events_id_seq'::regclass);
--

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,851 @@
-- Name: announcement_reads announcement_reads_announcement_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.announcement_reads
ADD CONSTRAINT announcement_reads_announcement_id_fkey FOREIGN KEY (announcement_id) REFERENCES public.announcements(id);
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: announcement_reads announcement_reads_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.announcement_reads
ADD CONSTRAINT announcement_reads_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: announcements announcements_author_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.announcements
ADD CONSTRAINT announcements_author_id_fkey FOREIGN KEY (author_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: api_key_provider_mappings api_key_provider_mappings_api_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.api_key_provider_mappings
ADD CONSTRAINT api_key_provider_mappings_api_key_id_fkey FOREIGN KEY (api_key_id) REFERENCES public.api_keys(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: api_key_provider_mappings api_key_provider_mappings_provider_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.api_key_provider_mappings
ADD CONSTRAINT api_key_provider_mappings_provider_id_fkey FOREIGN KEY (provider_id) REFERENCES public.providers(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: api_keys api_keys_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.api_keys
ADD CONSTRAINT api_keys_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: audit_logs audit_logs_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.audit_logs
ADD CONSTRAINT audit_logs_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: billing_rules billing_rules_global_model_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.billing_rules
ADD CONSTRAINT billing_rules_global_model_id_fkey FOREIGN KEY (global_model_id) REFERENCES public.global_models(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: billing_rules billing_rules_model_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.billing_rules
ADD CONSTRAINT billing_rules_model_id_fkey FOREIGN KEY (model_id) REFERENCES public.models(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: provider_api_keys fk_provider_api_keys_provider; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.provider_api_keys
ADD CONSTRAINT fk_provider_api_keys_provider FOREIGN KEY (provider_id) REFERENCES public.providers(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: gemini_file_mappings gemini_file_mappings_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.gemini_file_mappings
ADD CONSTRAINT gemini_file_mappings_key_id_fkey FOREIGN KEY (key_id) REFERENCES public.provider_api_keys(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: gemini_file_mappings gemini_file_mappings_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.gemini_file_mappings
ADD CONSTRAINT gemini_file_mappings_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: management_tokens management_tokens_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.management_tokens
ADD CONSTRAINT management_tokens_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: models models_global_model_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.models
ADD CONSTRAINT models_global_model_id_fkey FOREIGN KEY (global_model_id) REFERENCES public.global_models(id);
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: models models_provider_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.models
ADD CONSTRAINT models_provider_id_fkey FOREIGN KEY (provider_id) REFERENCES public.providers(id);
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: payment_callbacks payment_callbacks_payment_order_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.payment_callbacks
ADD CONSTRAINT payment_callbacks_payment_order_id_fkey FOREIGN KEY (payment_order_id) REFERENCES public.payment_orders(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: payment_orders payment_orders_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.payment_orders
ADD CONSTRAINT payment_orders_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: payment_orders payment_orders_wallet_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.payment_orders
ADD CONSTRAINT payment_orders_wallet_id_fkey FOREIGN KEY (wallet_id) REFERENCES public.wallets(id) ON DELETE RESTRICT;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: provider_endpoints provider_endpoints_provider_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.provider_endpoints
ADD CONSTRAINT provider_endpoints_provider_id_fkey FOREIGN KEY (provider_id) REFERENCES public.providers(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: provider_usage_tracking provider_usage_tracking_provider_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.provider_usage_tracking
ADD CONSTRAINT provider_usage_tracking_provider_id_fkey FOREIGN KEY (provider_id) REFERENCES public.providers(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: proxy_node_events proxy_node_events_node_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.proxy_node_events
ADD CONSTRAINT proxy_node_events_node_id_fkey FOREIGN KEY (node_id) REFERENCES public.proxy_nodes(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: proxy_nodes proxy_nodes_registered_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.proxy_nodes
ADD CONSTRAINT proxy_nodes_registered_by_fkey FOREIGN KEY (registered_by) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: refund_requests refund_requests_approved_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.refund_requests
ADD CONSTRAINT refund_requests_approved_by_fkey FOREIGN KEY (approved_by) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: refund_requests refund_requests_payment_order_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.refund_requests
ADD CONSTRAINT refund_requests_payment_order_id_fkey FOREIGN KEY (payment_order_id) REFERENCES public.payment_orders(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: refund_requests refund_requests_processed_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.refund_requests
ADD CONSTRAINT refund_requests_processed_by_fkey FOREIGN KEY (processed_by) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: refund_requests refund_requests_requested_by_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.refund_requests
ADD CONSTRAINT refund_requests_requested_by_fkey FOREIGN KEY (requested_by) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: refund_requests refund_requests_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.refund_requests
ADD CONSTRAINT refund_requests_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: refund_requests refund_requests_wallet_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.refund_requests
ADD CONSTRAINT refund_requests_wallet_id_fkey FOREIGN KEY (wallet_id) REFERENCES public.wallets(id) ON DELETE RESTRICT;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: request_candidates request_candidates_api_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.request_candidates
ADD CONSTRAINT request_candidates_api_key_id_fkey FOREIGN KEY (api_key_id) REFERENCES public.api_keys(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: request_candidates request_candidates_endpoint_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.request_candidates
ADD CONSTRAINT request_candidates_endpoint_id_fkey FOREIGN KEY (endpoint_id) REFERENCES public.provider_endpoints(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: request_candidates request_candidates_provider_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.request_candidates
ADD CONSTRAINT request_candidates_provider_id_fkey FOREIGN KEY (provider_id) REFERENCES public.providers(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: request_candidates request_candidates_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.request_candidates
ADD CONSTRAINT request_candidates_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: stats_daily_api_key stats_daily_api_key_api_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.stats_daily_api_key
ADD CONSTRAINT stats_daily_api_key_api_key_id_fkey FOREIGN KEY (api_key_id) REFERENCES public.api_keys(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: stats_user_daily stats_user_daily_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.stats_user_daily
ADD CONSTRAINT stats_user_daily_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: usage usage_api_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.usage
ADD CONSTRAINT usage_api_key_id_fkey FOREIGN KEY (api_key_id) REFERENCES public.api_keys(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: usage usage_provider_api_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.usage
ADD CONSTRAINT usage_provider_api_key_id_fkey FOREIGN KEY (provider_api_key_id) REFERENCES public.provider_api_keys(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: usage usage_provider_endpoint_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.usage
ADD CONSTRAINT usage_provider_endpoint_id_fkey FOREIGN KEY (provider_endpoint_id) REFERENCES public.provider_endpoints(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: usage usage_provider_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.usage
ADD CONSTRAINT usage_provider_id_fkey FOREIGN KEY (provider_id) REFERENCES public.providers(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: usage usage_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.usage
ADD CONSTRAINT usage_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: usage usage_wallet_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.usage
ADD CONSTRAINT usage_wallet_id_fkey FOREIGN KEY (wallet_id) REFERENCES public.wallets(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: user_model_usage_counts user_model_usage_counts_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.user_model_usage_counts
ADD CONSTRAINT user_model_usage_counts_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: user_oauth_links user_oauth_links_provider_type_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.user_oauth_links
ADD CONSTRAINT user_oauth_links_provider_type_fkey FOREIGN KEY (provider_type) REFERENCES public.oauth_providers(provider_type) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: user_oauth_links user_oauth_links_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.user_oauth_links
ADD CONSTRAINT user_oauth_links_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: user_preferences user_preferences_default_provider_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.user_preferences
ADD CONSTRAINT user_preferences_default_provider_id_fkey FOREIGN KEY (default_provider_id) REFERENCES public.providers(id);
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: user_preferences user_preferences_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.user_preferences
ADD CONSTRAINT user_preferences_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: user_sessions user_sessions_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.user_sessions
ADD CONSTRAINT user_sessions_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: video_tasks video_tasks_api_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.video_tasks
ADD CONSTRAINT video_tasks_api_key_id_fkey FOREIGN KEY (api_key_id) REFERENCES public.api_keys(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: video_tasks video_tasks_endpoint_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.video_tasks
ADD CONSTRAINT video_tasks_endpoint_id_fkey FOREIGN KEY (endpoint_id) REFERENCES public.provider_endpoints(id);
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: video_tasks video_tasks_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.video_tasks
ADD CONSTRAINT video_tasks_key_id_fkey FOREIGN KEY (key_id) REFERENCES public.provider_api_keys(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: video_tasks video_tasks_provider_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.video_tasks
ADD CONSTRAINT video_tasks_provider_id_fkey FOREIGN KEY (provider_id) REFERENCES public.providers(id);
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: video_tasks video_tasks_remixed_from_task_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.video_tasks
ADD CONSTRAINT video_tasks_remixed_from_task_id_fkey FOREIGN KEY (remixed_from_task_id) REFERENCES public.video_tasks(id);
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: video_tasks video_tasks_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.video_tasks
ADD CONSTRAINT video_tasks_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: wallet_daily_usage_ledgers wallet_daily_usage_ledgers_wallet_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.wallet_daily_usage_ledgers
ADD CONSTRAINT wallet_daily_usage_ledgers_wallet_id_fkey FOREIGN KEY (wallet_id) REFERENCES public.wallets(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: wallet_transactions wallet_transactions_operator_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.wallet_transactions
ADD CONSTRAINT wallet_transactions_operator_id_fkey FOREIGN KEY (operator_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: wallet_transactions wallet_transactions_wallet_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.wallet_transactions
ADD CONSTRAINT wallet_transactions_wallet_id_fkey FOREIGN KEY (wallet_id) REFERENCES public.wallets(id) ON DELETE CASCADE;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: wallets wallets_api_key_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.wallets
ADD CONSTRAINT wallets_api_key_id_fkey FOREIGN KEY (api_key_id) REFERENCES public.api_keys(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;
--
-- Name: wallets wallets_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: -
--
DO $mig$ BEGIN
ALTER TABLE ONLY public.wallets
ADD CONSTRAINT wallets_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE SET NULL;
EXCEPTION
WHEN duplicate_object THEN NULL;
WHEN duplicate_table THEN NULL;
WHEN invalid_table_definition THEN NULL;
END $mig$;

View File

@@ -0,0 +1,9 @@
-- Restore a normal lookup path before sqlx records this migration in the
-- same transaction. sqlx inserts into `_sqlx_migrations` unqualified.
SELECT pg_catalog.set_config('search_path', 'public', true);
--
-- PostgreSQL database dump complete
--

View File

@@ -0,0 +1,6 @@
001_types_and_tables.sql
002_defaults.sql
003_constraints.sql
004_indexes.sql
005_foreign_keys.sql
006_footer.sql

View File

@@ -0,0 +1,116 @@
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY,
external_id TEXT,
email TEXT UNIQUE,
username TEXT UNIQUE,
password_hash TEXT,
role TEXT,
auth_source TEXT NOT NULL DEFAULT 'local',
email_verified INTEGER NOT NULL DEFAULT 0,
is_active INTEGER NOT NULL DEFAULT 1,
is_deleted INTEGER NOT NULL DEFAULT 0,
allowed_models TEXT,
allowed_providers TEXT,
allowed_api_formats TEXT,
model_capability_settings TEXT,
rate_limit INTEGER,
metadata TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
last_login_at INTEGER
);
CREATE TABLE IF NOT EXISTS api_keys (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
key_hash TEXT NOT NULL UNIQUE,
key_encrypted TEXT,
name TEXT,
key_prefix TEXT,
status TEXT NOT NULL DEFAULT 'active',
allowed_models TEXT,
allowed_providers TEXT,
allowed_api_formats TEXT,
rate_limit INTEGER DEFAULT 100,
concurrent_limit INTEGER,
force_capabilities TEXT,
is_active INTEGER NOT NULL DEFAULT 1,
is_locked INTEGER NOT NULL DEFAULT 0,
is_standalone INTEGER NOT NULL DEFAULT 0,
auto_delete_on_expiry INTEGER NOT NULL DEFAULT 0,
total_requests INTEGER NOT NULL DEFAULT 0,
total_tokens INTEGER NOT NULL DEFAULT 0,
total_cost_usd REAL NOT NULL DEFAULT 0,
metadata TEXT,
expires_at INTEGER,
last_used_at INTEGER,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS api_keys_user_id_idx ON api_keys (user_id);
CREATE TABLE IF NOT EXISTS audit_logs (
id TEXT PRIMARY KEY,
event_type TEXT NOT NULL,
user_id TEXT,
api_key_id TEXT,
description TEXT NOT NULL,
ip_address TEXT,
user_agent TEXT,
request_id TEXT,
event_metadata TEXT,
status_code INTEGER,
error_message TEXT,
created_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS audit_logs_created_at_idx ON audit_logs (created_at);
CREATE INDEX IF NOT EXISTS audit_logs_event_type_idx ON audit_logs (event_type);
CREATE INDEX IF NOT EXISTS audit_logs_request_id_idx ON audit_logs (request_id);
CREATE INDEX IF NOT EXISTS audit_logs_user_id_idx ON audit_logs (user_id);
CREATE TABLE IF NOT EXISTS announcements (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
content TEXT NOT NULL,
type TEXT NOT NULL DEFAULT 'info',
priority INTEGER NOT NULL DEFAULT 0,
author_id TEXT,
is_active INTEGER NOT NULL DEFAULT 1,
is_pinned INTEGER NOT NULL DEFAULT 0,
start_time INTEGER,
end_time INTEGER,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS announcements_author_id_idx ON announcements (author_id);
CREATE INDEX IF NOT EXISTS announcements_created_at_idx ON announcements (created_at);
CREATE INDEX IF NOT EXISTS announcements_is_active_idx ON announcements (is_active);
CREATE TABLE IF NOT EXISTS announcement_reads (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
announcement_id TEXT NOT NULL,
read_at INTEGER NOT NULL,
UNIQUE (user_id, announcement_id)
);
CREATE INDEX IF NOT EXISTS announcement_reads_announcement_id_idx ON announcement_reads (announcement_id);
CREATE INDEX IF NOT EXISTS announcement_reads_user_id_idx ON announcement_reads (user_id);
CREATE TABLE IF NOT EXISTS management_tokens (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
name TEXT NOT NULL,
description TEXT,
token_hash TEXT NOT NULL UNIQUE,
token_prefix TEXT,
allowed_ips TEXT,
expires_at INTEGER,
last_used_at INTEGER,
last_used_ip TEXT,
usage_count INTEGER NOT NULL DEFAULT 0,
is_active INTEGER NOT NULL DEFAULT 1,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (user_id, name)
);
CREATE INDEX IF NOT EXISTS management_tokens_user_id_idx ON management_tokens (user_id);

View File

@@ -0,0 +1,299 @@
CREATE TABLE IF NOT EXISTS billing_rules (
id TEXT PRIMARY KEY,
global_model_id TEXT,
model_id TEXT,
name TEXT NOT NULL,
task_type TEXT NOT NULL DEFAULT 'chat',
expression TEXT NOT NULL,
variables TEXT NOT NULL DEFAULT '{}',
dimension_mappings TEXT NOT NULL DEFAULT '{}',
is_enabled INTEGER NOT NULL DEFAULT 1,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
CHECK (
(global_model_id IS NOT NULL AND model_id IS NULL)
OR (global_model_id IS NULL AND model_id IS NOT NULL)
)
);
CREATE UNIQUE INDEX IF NOT EXISTS uq_billing_rules_global_model_task
ON billing_rules (global_model_id, task_type)
WHERE is_enabled = 1 AND global_model_id IS NOT NULL;
CREATE UNIQUE INDEX IF NOT EXISTS uq_billing_rules_model_task
ON billing_rules (model_id, task_type)
WHERE is_enabled = 1 AND model_id IS NOT NULL;
CREATE TABLE IF NOT EXISTS dimension_collectors (
id TEXT PRIMARY KEY,
api_format TEXT NOT NULL,
task_type TEXT NOT NULL,
dimension_name TEXT NOT NULL,
source_type TEXT NOT NULL,
source_path TEXT,
value_type TEXT NOT NULL DEFAULT 'float',
transform_expression TEXT,
default_value TEXT,
priority INTEGER NOT NULL DEFAULT 0,
is_enabled INTEGER NOT NULL DEFAULT 1,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
CHECK (
(source_type = 'computed' AND source_path IS NULL AND transform_expression IS NOT NULL)
OR (source_type <> 'computed' AND source_path IS NOT NULL)
)
);
CREATE UNIQUE INDEX IF NOT EXISTS uq_dimension_collectors_enabled
ON dimension_collectors (api_format, task_type, dimension_name, priority)
WHERE is_enabled = 1;
CREATE TABLE IF NOT EXISTS providers (
id TEXT PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
description TEXT,
website TEXT,
provider_type TEXT NOT NULL,
billing_type TEXT,
monthly_quota_usd REAL,
monthly_used_usd REAL,
quota_reset_day INTEGER,
quota_last_reset_at INTEGER,
quota_expires_at INTEGER,
enabled INTEGER NOT NULL DEFAULT 1,
is_active INTEGER NOT NULL DEFAULT 1,
priority INTEGER NOT NULL DEFAULT 0,
provider_priority INTEGER NOT NULL DEFAULT 100,
keep_priority_on_conversion INTEGER NOT NULL DEFAULT 0,
enable_format_conversion INTEGER NOT NULL DEFAULT 1,
concurrent_limit INTEGER,
max_retries INTEGER,
proxy TEXT,
request_timeout REAL,
stream_first_byte_timeout REAL,
config TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS provider_api_keys (
id TEXT PRIMARY KEY,
provider_id TEXT NOT NULL,
name TEXT NOT NULL,
api_key TEXT,
encrypted_key TEXT,
auth_type TEXT NOT NULL DEFAULT 'api_key',
auth_config TEXT,
note TEXT,
internal_priority INTEGER NOT NULL DEFAULT 50,
capabilities TEXT,
api_formats TEXT,
auth_type_by_format TEXT,
allow_auth_channel_mismatch_formats TEXT,
rate_multipliers TEXT,
global_priority_by_format TEXT,
allowed_models TEXT,
expires_at INTEGER,
cache_ttl_minutes INTEGER NOT NULL DEFAULT 5,
max_probe_interval_minutes INTEGER NOT NULL DEFAULT 32,
proxy TEXT,
fingerprint TEXT,
concurrent_limit INTEGER,
learned_rpm_limit INTEGER,
concurrent_429_count INTEGER NOT NULL DEFAULT 0,
rpm_429_count INTEGER NOT NULL DEFAULT 0,
last_429_at INTEGER,
last_429_type TEXT,
adjustment_history TEXT,
utilization_samples TEXT,
last_probe_increase_at INTEGER,
last_rpm_peak INTEGER,
request_count INTEGER NOT NULL DEFAULT 0,
total_tokens INTEGER NOT NULL DEFAULT 0,
total_cost_usd REAL NOT NULL DEFAULT 0,
success_count INTEGER NOT NULL DEFAULT 0,
error_count INTEGER NOT NULL DEFAULT 0,
total_response_time_ms INTEGER NOT NULL DEFAULT 0,
last_used_at INTEGER,
auto_fetch_models INTEGER NOT NULL DEFAULT 0,
last_models_fetch_at INTEGER,
last_models_fetch_error TEXT,
locked_models TEXT,
model_include_patterns TEXT,
model_exclude_patterns TEXT,
upstream_metadata TEXT,
oauth_invalid_at INTEGER,
oauth_invalid_reason TEXT,
status_snapshot TEXT,
health_by_format TEXT,
circuit_breaker_by_format TEXT,
status TEXT NOT NULL DEFAULT 'active',
is_active INTEGER NOT NULL DEFAULT 1,
weight INTEGER NOT NULL DEFAULT 1,
rpm_limit INTEGER,
metadata TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS provider_api_keys_provider_id_idx ON provider_api_keys (provider_id);
CREATE TABLE IF NOT EXISTS gemini_file_mappings (
id TEXT PRIMARY KEY,
file_name TEXT NOT NULL UNIQUE,
key_id TEXT NOT NULL,
user_id TEXT,
display_name TEXT,
mime_type TEXT,
source_hash TEXT,
created_at INTEGER NOT NULL,
expires_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS gemini_file_mappings_key_id_idx ON gemini_file_mappings (key_id);
CREATE INDEX IF NOT EXISTS gemini_file_mappings_user_id_idx ON gemini_file_mappings (user_id);
CREATE INDEX IF NOT EXISTS gemini_file_mappings_expires_at_idx ON gemini_file_mappings (expires_at);
CREATE INDEX IF NOT EXISTS gemini_file_mappings_source_hash_idx ON gemini_file_mappings (source_hash);
CREATE TABLE IF NOT EXISTS request_candidates (
id TEXT PRIMARY KEY,
request_id TEXT NOT NULL,
user_id TEXT,
api_key_id TEXT,
username TEXT,
api_key_name TEXT,
candidate_index INTEGER NOT NULL,
retry_index INTEGER NOT NULL DEFAULT 0,
provider_id TEXT,
endpoint_id TEXT,
key_id TEXT,
status TEXT NOT NULL,
skip_reason TEXT,
is_cached INTEGER NOT NULL DEFAULT 0,
status_code INTEGER,
error_type TEXT,
error_message TEXT,
latency_ms INTEGER,
concurrent_requests INTEGER,
extra_data TEXT,
required_capabilities TEXT,
created_at INTEGER NOT NULL,
started_at INTEGER,
finished_at INTEGER,
UNIQUE (request_id, candidate_index, retry_index)
);
CREATE INDEX IF NOT EXISTS request_candidates_request_id_idx ON request_candidates (request_id);
CREATE INDEX IF NOT EXISTS request_candidates_provider_id_idx ON request_candidates (provider_id);
CREATE INDEX IF NOT EXISTS request_candidates_endpoint_id_idx ON request_candidates (endpoint_id);
CREATE INDEX IF NOT EXISTS request_candidates_status_idx ON request_candidates (status);
CREATE INDEX IF NOT EXISTS request_candidates_created_at_idx ON request_candidates (created_at);
CREATE INDEX IF NOT EXISTS request_candidates_endpoint_status_created_idx ON request_candidates (endpoint_id, status, created_at);
CREATE TABLE IF NOT EXISTS video_tasks (
id TEXT PRIMARY KEY,
short_id TEXT UNIQUE,
request_id TEXT NOT NULL UNIQUE,
user_id TEXT,
api_key_id TEXT,
username TEXT,
api_key_name TEXT,
external_task_id TEXT,
provider_id TEXT,
endpoint_id TEXT,
key_id TEXT,
client_api_format TEXT,
provider_api_format TEXT,
format_converted INTEGER NOT NULL DEFAULT 0,
model TEXT,
prompt TEXT,
original_request_body TEXT,
duration_seconds INTEGER,
resolution TEXT,
aspect_ratio TEXT,
size TEXT,
status TEXT NOT NULL DEFAULT 'pending',
progress_percent INTEGER NOT NULL DEFAULT 0,
progress_message TEXT,
retry_count INTEGER NOT NULL DEFAULT 0,
poll_interval_seconds INTEGER NOT NULL DEFAULT 10,
next_poll_at INTEGER,
poll_count INTEGER NOT NULL DEFAULT 0,
max_poll_count INTEGER NOT NULL DEFAULT 360,
created_at INTEGER NOT NULL,
submitted_at INTEGER,
completed_at INTEGER,
updated_at INTEGER NOT NULL,
error_code TEXT,
error_message TEXT,
video_url TEXT,
request_metadata TEXT
);
CREATE INDEX IF NOT EXISTS video_tasks_external_id_idx ON video_tasks (external_task_id);
CREATE INDEX IF NOT EXISTS video_tasks_next_poll_idx ON video_tasks (next_poll_at);
CREATE INDEX IF NOT EXISTS video_tasks_request_id_idx ON video_tasks (request_id);
CREATE INDEX IF NOT EXISTS video_tasks_user_status_idx ON video_tasks (user_id, status);
CREATE INDEX IF NOT EXISTS video_tasks_api_key_id_idx ON video_tasks (api_key_id);
CREATE INDEX IF NOT EXISTS video_tasks_provider_id_idx ON video_tasks (provider_id);
CREATE INDEX IF NOT EXISTS video_tasks_endpoint_id_idx ON video_tasks (endpoint_id);
CREATE INDEX IF NOT EXISTS video_tasks_key_id_idx ON video_tasks (key_id);
CREATE TABLE IF NOT EXISTS provider_endpoints (
id TEXT PRIMARY KEY,
provider_id TEXT NOT NULL,
name TEXT NOT NULL,
base_url TEXT NOT NULL,
api_format TEXT,
api_family TEXT,
endpoint_kind TEXT,
enabled INTEGER NOT NULL DEFAULT 1,
is_active INTEGER NOT NULL DEFAULT 1,
health_score REAL NOT NULL DEFAULT 1.0,
weight INTEGER NOT NULL DEFAULT 1,
header_rules TEXT,
body_rules TEXT,
max_retries INTEGER,
custom_path TEXT,
metadata TEXT,
config TEXT,
format_acceptance_config TEXT,
proxy TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS provider_endpoints_provider_id_idx ON provider_endpoints (provider_id);
CREATE TABLE IF NOT EXISTS models (
id TEXT PRIMARY KEY,
provider_id TEXT NOT NULL,
global_model_id TEXT,
provider_model_name TEXT NOT NULL,
global_model_name TEXT,
api_format TEXT,
enabled INTEGER NOT NULL DEFAULT 1,
is_active INTEGER NOT NULL DEFAULT 1,
is_available INTEGER NOT NULL DEFAULT 1,
price_per_request REAL,
tiered_pricing TEXT,
supports_vision INTEGER,
supports_function_calling INTEGER,
supports_streaming INTEGER,
supports_extended_thinking INTEGER,
supports_image_generation INTEGER,
provider_model_mappings TEXT,
config TEXT,
metadata TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS models_provider_id_idx ON models (provider_id);
CREATE TABLE IF NOT EXISTS global_models (
id TEXT PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
display_name TEXT,
enabled INTEGER NOT NULL DEFAULT 1,
is_active INTEGER NOT NULL DEFAULT 1,
default_price_per_request REAL,
default_tiered_pricing TEXT,
supported_capabilities TEXT,
usage_count INTEGER NOT NULL DEFAULT 0,
config TEXT,
metadata TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);

View File

@@ -0,0 +1,67 @@
CREATE TABLE IF NOT EXISTS system_configs (
id TEXT PRIMARY KEY,
key TEXT NOT NULL UNIQUE,
value TEXT NOT NULL,
description TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS auth_modules (
id TEXT PRIMARY KEY,
module_type TEXT NOT NULL UNIQUE,
enabled INTEGER NOT NULL DEFAULT 1,
config TEXT NOT NULL,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS oauth_providers (
provider_type TEXT PRIMARY KEY,
display_name TEXT NOT NULL,
client_id TEXT NOT NULL,
client_secret_encrypted TEXT,
authorization_url_override TEXT,
token_url_override TEXT,
userinfo_url_override TEXT,
scopes TEXT,
redirect_uri TEXT NOT NULL,
frontend_callback_url TEXT NOT NULL,
attribute_mapping TEXT,
extra_config TEXT,
is_enabled INTEGER NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS ldap_configs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
server_url TEXT NOT NULL,
bind_dn TEXT NOT NULL,
bind_password_encrypted TEXT,
base_dn TEXT NOT NULL,
user_search_filter TEXT DEFAULT '(uid={username})' NOT NULL,
username_attr TEXT DEFAULT 'uid' NOT NULL,
email_attr TEXT DEFAULT 'mail' NOT NULL,
display_name_attr TEXT DEFAULT 'cn' NOT NULL,
is_enabled INTEGER NOT NULL DEFAULT 0,
is_exclusive INTEGER NOT NULL DEFAULT 0,
use_starttls INTEGER NOT NULL DEFAULT 0,
connect_timeout INTEGER NOT NULL DEFAULT 10,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS user_oauth_links (
id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
provider_type TEXT NOT NULL,
provider_user_id TEXT NOT NULL,
provider_username TEXT,
provider_email TEXT,
extra_data TEXT,
linked_at INTEGER NOT NULL,
last_login_at INTEGER
);
CREATE INDEX IF NOT EXISTS user_oauth_links_provider_type_idx ON user_oauth_links (provider_type);
CREATE INDEX IF NOT EXISTS user_oauth_links_user_id_idx ON user_oauth_links (user_id);

View File

@@ -0,0 +1,39 @@
CREATE TABLE IF NOT EXISTS proxy_nodes (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
ip TEXT NOT NULL,
port INTEGER NOT NULL,
region TEXT,
status TEXT NOT NULL DEFAULT 'online',
registered_by TEXT,
last_heartbeat_at INTEGER,
heartbeat_interval INTEGER NOT NULL DEFAULT 30,
active_connections INTEGER NOT NULL DEFAULT 0,
total_requests INTEGER NOT NULL DEFAULT 0,
avg_latency_ms REAL,
is_manual INTEGER NOT NULL DEFAULT 0,
proxy_url TEXT,
proxy_username TEXT,
proxy_password TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
remote_config TEXT,
config_version INTEGER NOT NULL DEFAULT 0,
hardware_info TEXT,
estimated_max_concurrency INTEGER,
tunnel_mode INTEGER NOT NULL DEFAULT 0,
tunnel_connected INTEGER NOT NULL DEFAULT 0,
tunnel_connected_at INTEGER,
failed_requests INTEGER NOT NULL DEFAULT 0,
dns_failures INTEGER NOT NULL DEFAULT 0,
stream_errors INTEGER NOT NULL DEFAULT 0,
proxy_metadata TEXT
);
CREATE TABLE IF NOT EXISTS proxy_node_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
node_id TEXT NOT NULL,
event_type TEXT NOT NULL,
detail TEXT,
created_at INTEGER NOT NULL
);

View File

@@ -0,0 +1,202 @@
CREATE TABLE IF NOT EXISTS wallets (
id TEXT PRIMARY KEY,
user_id TEXT UNIQUE,
api_key_id TEXT UNIQUE,
balance REAL NOT NULL DEFAULT 0,
gift_balance REAL NOT NULL DEFAULT 0,
limit_mode TEXT NOT NULL DEFAULT 'finite',
currency TEXT NOT NULL DEFAULT 'USD',
status TEXT NOT NULL DEFAULT 'active',
total_recharged REAL NOT NULL DEFAULT 0,
total_consumed REAL NOT NULL DEFAULT 0,
total_refunded REAL NOT NULL DEFAULT 0,
total_adjusted REAL NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS wallets_api_key_id_idx ON wallets (api_key_id);
CREATE INDEX IF NOT EXISTS wallets_user_id_idx ON wallets (user_id);
CREATE TABLE IF NOT EXISTS wallet_transactions (
id TEXT PRIMARY KEY,
wallet_id TEXT NOT NULL,
category TEXT NOT NULL,
reason_code TEXT NOT NULL,
amount REAL NOT NULL,
balance_before REAL NOT NULL,
balance_after REAL NOT NULL,
recharge_balance_before REAL NOT NULL,
recharge_balance_after REAL NOT NULL,
gift_balance_before REAL NOT NULL,
gift_balance_after REAL NOT NULL,
link_type TEXT,
link_id TEXT,
operator_id TEXT,
description TEXT,
created_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_wallet_tx_wallet_created
ON wallet_transactions (wallet_id, created_at);
CREATE INDEX IF NOT EXISTS idx_wallet_tx_category_created
ON wallet_transactions (category, created_at);
CREATE INDEX IF NOT EXISTS idx_wallet_tx_reason_created
ON wallet_transactions (reason_code, created_at);
CREATE INDEX IF NOT EXISTS idx_wallet_tx_link
ON wallet_transactions (link_type, link_id);
CREATE INDEX IF NOT EXISTS ix_wallet_transactions_operator_id
ON wallet_transactions (operator_id);
CREATE TABLE IF NOT EXISTS wallet_daily_usage_ledgers (
id TEXT PRIMARY KEY,
wallet_id TEXT NOT NULL,
billing_date TEXT NOT NULL,
billing_timezone TEXT NOT NULL,
total_cost_usd REAL NOT NULL DEFAULT 0,
total_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
first_finalized_at INTEGER,
last_finalized_at INTEGER,
aggregated_at INTEGER NOT NULL,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_wallet_daily_usage_wallet_date
ON wallet_daily_usage_ledgers (wallet_id, billing_timezone, billing_date);
CREATE TABLE IF NOT EXISTS payment_orders (
id TEXT PRIMARY KEY,
order_no TEXT NOT NULL UNIQUE,
wallet_id TEXT NOT NULL,
user_id TEXT,
amount_usd REAL NOT NULL,
pay_amount REAL,
pay_currency TEXT,
exchange_rate REAL,
refunded_amount_usd REAL NOT NULL DEFAULT 0,
refundable_amount_usd REAL NOT NULL DEFAULT 0,
payment_method TEXT NOT NULL,
gateway_order_id TEXT,
gateway_response TEXT,
status TEXT NOT NULL DEFAULT 'pending',
created_at INTEGER NOT NULL,
paid_at INTEGER,
credited_at INTEGER,
expires_at INTEGER
);
CREATE INDEX IF NOT EXISTS idx_payment_orders_wallet_created
ON payment_orders (wallet_id, created_at);
CREATE INDEX IF NOT EXISTS idx_payment_orders_user_created
ON payment_orders (user_id, created_at);
CREATE INDEX IF NOT EXISTS idx_payment_orders_status
ON payment_orders (status);
CREATE INDEX IF NOT EXISTS idx_payment_orders_gateway_order_id
ON payment_orders (gateway_order_id);
CREATE TABLE IF NOT EXISTS payment_callbacks (
id TEXT PRIMARY KEY,
payment_order_id TEXT,
payment_method TEXT NOT NULL,
callback_key TEXT NOT NULL UNIQUE,
order_no TEXT,
gateway_order_id TEXT,
payload_hash TEXT,
signature_valid INTEGER NOT NULL DEFAULT 0,
status TEXT NOT NULL DEFAULT 'received',
payload TEXT,
error_message TEXT,
created_at INTEGER NOT NULL,
processed_at INTEGER
);
CREATE INDEX IF NOT EXISTS idx_payment_callbacks_order
ON payment_callbacks (order_no);
CREATE INDEX IF NOT EXISTS idx_payment_callbacks_gateway_order
ON payment_callbacks (gateway_order_id);
CREATE INDEX IF NOT EXISTS idx_payment_callbacks_created
ON payment_callbacks (created_at);
CREATE INDEX IF NOT EXISTS ix_payment_callbacks_payment_order_id
ON payment_callbacks (payment_order_id);
CREATE TABLE IF NOT EXISTS refund_requests (
id TEXT PRIMARY KEY,
refund_no TEXT NOT NULL UNIQUE,
wallet_id TEXT NOT NULL,
user_id TEXT,
payment_order_id TEXT,
source_type TEXT NOT NULL,
source_id TEXT,
refund_mode TEXT NOT NULL,
amount_usd REAL NOT NULL,
status TEXT NOT NULL DEFAULT 'pending_approval',
reason TEXT,
requested_by TEXT,
approved_by TEXT,
processed_by TEXT,
gateway_refund_id TEXT,
payout_method TEXT,
payout_reference TEXT,
payout_proof TEXT,
failure_reason TEXT,
idempotency_key TEXT UNIQUE,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
processed_at INTEGER,
completed_at INTEGER
);
CREATE INDEX IF NOT EXISTS idx_refund_wallet_created
ON refund_requests (wallet_id, created_at);
CREATE INDEX IF NOT EXISTS idx_refund_user_created
ON refund_requests (user_id, created_at);
CREATE INDEX IF NOT EXISTS idx_refund_status
ON refund_requests (status);
CREATE INDEX IF NOT EXISTS ix_refund_requests_payment_order_id
ON refund_requests (payment_order_id);
CREATE INDEX IF NOT EXISTS ix_refund_requests_requested_by
ON refund_requests (requested_by);
CREATE INDEX IF NOT EXISTS ix_refund_requests_approved_by
ON refund_requests (approved_by);
CREATE INDEX IF NOT EXISTS ix_refund_requests_processed_by
ON refund_requests (processed_by);
CREATE TABLE IF NOT EXISTS redeem_code_batches (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
amount_usd REAL NOT NULL,
currency TEXT NOT NULL DEFAULT 'USD',
balance_bucket TEXT NOT NULL DEFAULT 'gift',
total_count INTEGER NOT NULL,
status TEXT NOT NULL DEFAULT 'active',
description TEXT,
created_by TEXT,
expires_at INTEGER,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_redeem_code_batches_status
ON redeem_code_batches (status, created_at);
CREATE TABLE IF NOT EXISTS redeem_codes (
id TEXT PRIMARY KEY,
batch_id TEXT NOT NULL,
code_hash TEXT NOT NULL UNIQUE,
code_prefix TEXT NOT NULL,
code_suffix TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'active',
redeemed_by_user_id TEXT,
redeemed_wallet_id TEXT,
redeemed_payment_order_id TEXT,
redeemed_at INTEGER,
disabled_by TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_batch_created
ON redeem_codes (batch_id, created_at);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_status
ON redeem_codes (status, updated_at);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_redeemed_user
ON redeem_codes (redeemed_by_user_id, redeemed_at);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_redeemed_order
ON redeem_codes (redeemed_payment_order_id);

View File

@@ -0,0 +1,87 @@
CREATE TABLE IF NOT EXISTS "usage" (
request_id TEXT PRIMARY KEY,
id TEXT,
user_id TEXT,
api_key_id TEXT,
provider_name TEXT NOT NULL DEFAULT 'unknown',
model TEXT NOT NULL DEFAULT 'unknown',
target_model TEXT,
provider_id TEXT,
provider_endpoint_id TEXT,
provider_api_key_id TEXT,
request_type TEXT,
api_format TEXT,
api_family TEXT,
endpoint_kind TEXT,
endpoint_api_format TEXT,
provider_api_family TEXT,
provider_endpoint_kind TEXT,
has_format_conversion INTEGER NOT NULL DEFAULT 0,
is_stream INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
total_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_input_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_ephemeral_5m_input_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_ephemeral_1h_input_tokens INTEGER NOT NULL DEFAULT 0,
cache_read_input_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_cost_usd REAL NOT NULL DEFAULT 0,
cache_read_cost_usd REAL NOT NULL DEFAULT 0,
output_price_per_1m REAL,
status_code INTEGER,
error_message TEXT,
error_category TEXT,
response_time_ms INTEGER,
first_byte_time_ms INTEGER,
wallet_id TEXT,
status TEXT NOT NULL DEFAULT 'completed',
billing_status TEXT NOT NULL DEFAULT 'pending',
total_cost_usd REAL NOT NULL DEFAULT 0,
actual_total_cost_usd REAL NOT NULL DEFAULT 0,
request_metadata TEXT,
candidate_id TEXT,
candidate_index INTEGER,
key_name TEXT,
planner_kind TEXT,
route_family TEXT,
route_kind TEXT,
execution_path TEXT,
local_execution_runtime_miss_reason TEXT,
wallet_balance_before REAL,
wallet_balance_after REAL,
wallet_recharge_balance_before REAL,
wallet_recharge_balance_after REAL,
wallet_gift_balance_before REAL,
wallet_gift_balance_after REAL,
finalized_at INTEGER,
created_at_unix_ms INTEGER NOT NULL DEFAULT 0,
updated_at_unix_secs INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX IF NOT EXISTS usage_api_key_id_idx ON "usage" (api_key_id);
CREATE INDEX IF NOT EXISTS usage_billing_status_idx ON "usage" (billing_status);
CREATE INDEX IF NOT EXISTS usage_created_at_idx ON "usage" (created_at_unix_ms);
CREATE INDEX IF NOT EXISTS usage_provider_api_key_id_idx ON "usage" (provider_api_key_id);
CREATE INDEX IF NOT EXISTS usage_provider_id_idx ON "usage" (provider_id);
CREATE INDEX IF NOT EXISTS usage_request_id_idx ON "usage" (request_id);
CREATE INDEX IF NOT EXISTS usage_user_id_idx ON "usage" (user_id);
CREATE INDEX IF NOT EXISTS usage_wallet_id_idx ON "usage" (wallet_id);
CREATE TABLE IF NOT EXISTS usage_settlement_snapshots (
request_id TEXT PRIMARY KEY,
billing_status TEXT NOT NULL,
wallet_id TEXT,
wallet_balance_before REAL,
wallet_balance_after REAL,
wallet_recharge_balance_before REAL,
wallet_recharge_balance_after REAL,
wallet_gift_balance_before REAL,
wallet_gift_balance_after REAL,
provider_monthly_used_usd REAL,
finalized_at INTEGER,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS usage_settlement_snapshots_billing_status_idx
ON usage_settlement_snapshots (billing_status);
CREATE INDEX IF NOT EXISTS usage_settlement_snapshots_wallet_id_idx
ON usage_settlement_snapshots (wallet_id);

View File

@@ -0,0 +1,6 @@
001_identity.sql
002_provider_catalog.sql
003_auth_config.sql
004_proxy_nodes.sql
005_wallet_billing.sql
006_usage.sql

View File

@@ -0,0 +1,12 @@
# Generated Schema
This directory is generated by `aether-data-schema` from `../logical/*.toml`.
It is checked in only as an auditable compiler output and drift-detection fixture.
Do not edit files in this directory by hand. Update `../logical/*.toml`, then run:
```bash
bash crates/aether-data/schema/compose_schema.sh generate
```
Runtime migrations are not loaded from this directory. The executable SQL remains under `crates/aether-data/migrations/{postgres,mysql,sqlite}`, and the Postgres bootstrap snapshot is generated at build time from `crates/aether-data/schema/bootstrap/postgres` into the crate build output until a generated fragment is deliberately promoted into the driver-specific schema manifests.

View File

@@ -0,0 +1,180 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS users (
`id` VARCHAR(64) NOT NULL,
`external_id` VARCHAR(255),
`email` VARCHAR(320),
`username` VARCHAR(255),
`password_hash` VARCHAR(255),
`role` VARCHAR(64),
`auth_source` VARCHAR(64) NOT NULL DEFAULT 'local',
`email_verified` TINYINT(1) NOT NULL DEFAULT 0,
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
`is_deleted` TINYINT(1) NOT NULL DEFAULT 0,
`allowed_models` JSON,
`allowed_providers` JSON,
`allowed_api_formats` JSON,
`model_capability_settings` JSON,
`rate_limit` INT,
`metadata` JSON,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
`last_login_at` BIGINT,
`ldap_dn` VARCHAR(1024),
`ldap_username` VARCHAR(255),
PRIMARY KEY (`id`),
UNIQUE KEY users_email_key (`email`),
UNIQUE KEY users_username_key (`username`)
);
CREATE TABLE IF NOT EXISTS api_keys (
`id` VARCHAR(64) NOT NULL,
`user_id` VARCHAR(64) NOT NULL,
`key_hash` VARCHAR(255) NOT NULL,
`key_encrypted` LONGTEXT,
`name` VARCHAR(255),
`key_prefix` VARCHAR(64),
`status` VARCHAR(64) NOT NULL DEFAULT 'active',
`allowed_models` JSON,
`allowed_providers` JSON,
`allowed_api_formats` JSON,
`rate_limit` INT DEFAULT 100,
`concurrent_limit` INT,
`force_capabilities` JSON,
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
`is_locked` TINYINT(1) NOT NULL DEFAULT 0,
`is_standalone` TINYINT(1) NOT NULL DEFAULT 0,
`auto_delete_on_expiry` TINYINT(1) NOT NULL DEFAULT 0,
`total_requests` BIGINT NOT NULL DEFAULT 0,
`total_tokens` BIGINT NOT NULL DEFAULT 0,
`total_cost_usd` DOUBLE NOT NULL DEFAULT 0,
`metadata` JSON,
`expires_at` BIGINT,
`last_used_at` BIGINT,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY api_keys_key_hash_key (`key_hash`),
KEY api_keys_user_id_idx (`user_id`)
);
CREATE TABLE IF NOT EXISTS audit_logs (
`id` VARCHAR(64) NOT NULL,
`event_type` VARCHAR(64) NOT NULL,
`user_id` VARCHAR(64),
`api_key_id` VARCHAR(64),
`description` LONGTEXT NOT NULL,
`ip_address` VARCHAR(64),
`user_agent` VARCHAR(512),
`request_id` VARCHAR(128),
`event_metadata` JSON,
`status_code` INT,
`error_message` LONGTEXT,
`created_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
KEY audit_logs_created_at_idx (`created_at`),
KEY audit_logs_event_type_idx (`event_type`),
KEY audit_logs_request_id_idx (`request_id`),
KEY audit_logs_user_id_idx (`user_id`)
);
CREATE TABLE IF NOT EXISTS announcements (
`id` VARCHAR(64) NOT NULL,
`title` VARCHAR(200) NOT NULL,
`content` LONGTEXT NOT NULL,
`type` VARCHAR(32) NOT NULL DEFAULT 'info',
`priority` INT NOT NULL DEFAULT 0,
`author_id` VARCHAR(64),
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
`is_pinned` TINYINT(1) NOT NULL DEFAULT 0,
`start_time` BIGINT,
`end_time` BIGINT,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
KEY announcements_author_id_idx (`author_id`),
KEY announcements_created_at_idx (`created_at`),
KEY announcements_is_active_idx (`is_active`)
);
CREATE TABLE IF NOT EXISTS announcement_reads (
`id` VARCHAR(64) NOT NULL,
`user_id` VARCHAR(64) NOT NULL,
`announcement_id` VARCHAR(64) NOT NULL,
`read_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY uq_user_announcement (`user_id`, `announcement_id`),
KEY announcement_reads_announcement_id_idx (`announcement_id`),
KEY announcement_reads_user_id_idx (`user_id`)
);
CREATE TABLE IF NOT EXISTS management_tokens (
`id` VARCHAR(64) NOT NULL,
`user_id` VARCHAR(64) NOT NULL,
`name` VARCHAR(255) NOT NULL,
`description` LONGTEXT,
`token_hash` VARCHAR(255) NOT NULL,
`token_prefix` VARCHAR(64),
`allowed_ips` JSON,
`expires_at` BIGINT,
`last_used_at` BIGINT,
`last_used_ip` VARCHAR(255),
`usage_count` BIGINT NOT NULL DEFAULT 0,
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY management_tokens_token_hash_key (`token_hash`),
UNIQUE KEY uq_management_tokens_user_name (`user_id`, `name`),
KEY management_tokens_user_id_idx (`user_id`)
);
CREATE TABLE IF NOT EXISTS user_preferences (
`id` VARCHAR(64) NOT NULL,
`user_id` VARCHAR(64) NOT NULL,
`avatar_url` VARCHAR(500),
`bio` LONGTEXT,
`default_provider_id` VARCHAR(64),
`theme` VARCHAR(20) NOT NULL DEFAULT 'light',
`language` VARCHAR(10) NOT NULL DEFAULT 'zh-CN',
`timezone` VARCHAR(50) NOT NULL DEFAULT 'Asia/Shanghai',
`email_notifications` TINYINT(1) NOT NULL DEFAULT 1,
`usage_alerts` TINYINT(1) NOT NULL DEFAULT 1,
`announcement_notifications` TINYINT(1) NOT NULL DEFAULT 1,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY user_preferences_user_id_key (`user_id`),
KEY user_preferences_default_provider_id_idx (`default_provider_id`),
KEY user_preferences_user_id_idx (`user_id`)
);
CREATE TABLE IF NOT EXISTS user_sessions (
`id` VARCHAR(64) NOT NULL,
`user_id` VARCHAR(64) NOT NULL,
`client_device_id` VARCHAR(128) NOT NULL,
`device_label` VARCHAR(120),
`device_type` VARCHAR(20) NOT NULL DEFAULT 'unknown',
`browser_name` VARCHAR(50),
`browser_version` VARCHAR(50),
`os_name` VARCHAR(50),
`os_version` VARCHAR(50),
`device_model` VARCHAR(100),
`ip_address` VARCHAR(45),
`user_agent` VARCHAR(1000),
`client_hints` JSON,
`refresh_token_hash` VARCHAR(64) NOT NULL,
`prev_refresh_token_hash` VARCHAR(64),
`rotated_at` BIGINT,
`last_seen_at` BIGINT NOT NULL,
`expires_at` BIGINT NOT NULL,
`revoked_at` BIGINT,
`revoke_reason` VARCHAR(100),
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
KEY user_sessions_user_active_idx (`user_id`, `revoked_at`, `expires_at`),
KEY user_sessions_user_device_idx (`user_id`, `client_device_id`)
);

View File

@@ -0,0 +1,354 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS billing_rules (
`id` VARCHAR(64) NOT NULL,
`global_model_id` VARCHAR(64),
`model_id` VARCHAR(64),
`name` VARCHAR(255) NOT NULL,
`task_type` VARCHAR(64) NOT NULL DEFAULT 'chat',
`expression` LONGTEXT NOT NULL,
`variables` JSON NOT NULL,
`dimension_mappings` JSON NOT NULL,
`is_enabled` TINYINT(1) NOT NULL DEFAULT 1,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
KEY billing_rules_global_model_task_idx (`global_model_id`, `task_type`, `is_enabled`),
KEY billing_rules_model_task_idx (`model_id`, `task_type`, `is_enabled`)
);
CREATE TABLE IF NOT EXISTS dimension_collectors (
`id` VARCHAR(64) NOT NULL,
`api_format` VARCHAR(64) NOT NULL,
`task_type` VARCHAR(64) NOT NULL,
`dimension_name` VARCHAR(128) NOT NULL,
`source_type` VARCHAR(64) NOT NULL,
`source_path` VARCHAR(255),
`value_type` VARCHAR(64) NOT NULL DEFAULT 'float',
`transform_expression` LONGTEXT,
`default_value` VARCHAR(255),
`priority` INT NOT NULL DEFAULT 0,
`is_enabled` TINYINT(1) NOT NULL DEFAULT 1,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
KEY dimension_collectors_enabled_idx (`api_format`, `task_type`, `dimension_name`, `priority`, `is_enabled`)
);
CREATE TABLE IF NOT EXISTS providers (
`id` VARCHAR(64) NOT NULL,
`name` VARCHAR(255) NOT NULL,
`description` LONGTEXT,
`website` VARCHAR(500),
`provider_type` VARCHAR(64) NOT NULL,
`billing_type` VARCHAR(64),
`monthly_quota_usd` DOUBLE,
`monthly_used_usd` DOUBLE,
`quota_reset_day` INT,
`quota_last_reset_at` BIGINT,
`quota_expires_at` BIGINT,
`enabled` TINYINT(1) NOT NULL DEFAULT 1,
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
`priority` BIGINT NOT NULL DEFAULT 0,
`provider_priority` INT NOT NULL DEFAULT 100,
`keep_priority_on_conversion` TINYINT(1) NOT NULL DEFAULT 0,
`enable_format_conversion` TINYINT(1) NOT NULL DEFAULT 1,
`concurrent_limit` INT,
`max_retries` INT,
`proxy` JSON,
`request_timeout` DOUBLE,
`stream_first_byte_timeout` DOUBLE,
`config` JSON,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY providers_name_key (`name`)
);
CREATE TABLE IF NOT EXISTS provider_api_keys (
`id` VARCHAR(64) NOT NULL,
`provider_id` VARCHAR(64) NOT NULL,
`name` VARCHAR(255) NOT NULL,
`api_key` LONGTEXT,
`encrypted_key` LONGTEXT,
`auth_type` VARCHAR(32) NOT NULL DEFAULT 'api_key',
`auth_config` JSON,
`note` LONGTEXT,
`internal_priority` INT NOT NULL DEFAULT 50,
`capabilities` JSON,
`api_formats` JSON,
`auth_type_by_format` JSON,
`allow_auth_channel_mismatch_formats` JSON,
`rate_multipliers` JSON,
`global_priority_by_format` JSON,
`allowed_models` JSON,
`expires_at` BIGINT,
`cache_ttl_minutes` INT NOT NULL DEFAULT 5,
`max_probe_interval_minutes` INT NOT NULL DEFAULT 32,
`proxy` JSON,
`fingerprint` JSON,
`concurrent_limit` INT,
`learned_rpm_limit` INT,
`concurrent_429_count` INT NOT NULL DEFAULT 0,
`rpm_429_count` INT NOT NULL DEFAULT 0,
`last_429_at` BIGINT,
`last_429_type` VARCHAR(64),
`adjustment_history` JSON,
`utilization_samples` JSON,
`last_probe_increase_at` BIGINT,
`last_rpm_peak` INT,
`request_count` BIGINT NOT NULL DEFAULT 0,
`total_tokens` BIGINT NOT NULL DEFAULT 0,
`total_cost_usd` DOUBLE NOT NULL DEFAULT 0,
`success_count` BIGINT NOT NULL DEFAULT 0,
`error_count` BIGINT NOT NULL DEFAULT 0,
`total_response_time_ms` BIGINT NOT NULL DEFAULT 0,
`last_used_at` BIGINT,
`last_error_at` BIGINT,
`last_error_msg` LONGTEXT,
`auto_fetch_models` TINYINT(1) NOT NULL DEFAULT 0,
`last_models_fetch_at` BIGINT,
`last_models_fetch_error` LONGTEXT,
`locked_models` JSON,
`model_include_patterns` JSON,
`model_exclude_patterns` JSON,
`upstream_metadata` JSON,
`oauth_invalid_at` BIGINT,
`oauth_invalid_reason` VARCHAR(255),
`status_snapshot` JSON,
`health_by_format` JSON,
`circuit_breaker_by_format` JSON,
`status` VARCHAR(64) NOT NULL DEFAULT 'active',
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
`weight` BIGINT NOT NULL DEFAULT 1,
`rpm_limit` BIGINT,
`metadata` JSON,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
KEY provider_api_keys_provider_id_idx (`provider_id`)
);
CREATE TABLE IF NOT EXISTS api_key_provider_mappings (
`id` VARCHAR(64) NOT NULL,
`api_key_id` VARCHAR(64) NOT NULL,
`provider_id` VARCHAR(64) NOT NULL,
`priority_adjustment` INT NOT NULL DEFAULT 0,
`weight_multiplier` DOUBLE NOT NULL DEFAULT 1,
`is_enabled` TINYINT(1) NOT NULL DEFAULT 1,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY uq_apikey_provider (`api_key_id`, `provider_id`),
KEY api_key_provider_mappings_api_key_id_idx (`api_key_id`),
KEY api_key_provider_mappings_provider_id_idx (`provider_id`),
KEY idx_apikey_provider_enabled (`api_key_id`, `is_enabled`)
);
CREATE TABLE IF NOT EXISTS gemini_file_mappings (
`id` VARCHAR(64) NOT NULL,
`file_name` VARCHAR(512) NOT NULL,
`key_id` VARCHAR(64) NOT NULL,
`user_id` VARCHAR(64),
`display_name` VARCHAR(512),
`mime_type` VARCHAR(255),
`source_hash` VARCHAR(128),
`created_at` BIGINT NOT NULL,
`expires_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY gemini_file_mappings_file_name_key (`file_name`),
KEY gemini_file_mappings_key_id_idx (`key_id`),
KEY gemini_file_mappings_user_id_idx (`user_id`),
KEY gemini_file_mappings_expires_at_idx (`expires_at`),
KEY gemini_file_mappings_source_hash_idx (`source_hash`)
);
CREATE TABLE IF NOT EXISTS request_candidates (
`id` VARCHAR(64) NOT NULL,
`request_id` VARCHAR(128) NOT NULL,
`user_id` VARCHAR(64),
`api_key_id` VARCHAR(64),
`username` VARCHAR(255),
`api_key_name` VARCHAR(255),
`candidate_index` INT NOT NULL,
`retry_index` INT NOT NULL DEFAULT 0,
`provider_id` VARCHAR(64),
`endpoint_id` VARCHAR(64),
`key_id` VARCHAR(64),
`status` VARCHAR(32) NOT NULL,
`skip_reason` LONGTEXT,
`is_cached` TINYINT(1) NOT NULL DEFAULT 0,
`status_code` INT,
`error_type` VARCHAR(128),
`error_message` LONGTEXT,
`latency_ms` INT,
`concurrent_requests` INT,
`extra_data` JSON,
`required_capabilities` JSON,
`created_at` BIGINT NOT NULL,
`started_at` BIGINT,
`finished_at` BIGINT,
PRIMARY KEY (`id`),
UNIQUE KEY uq_request_candidate_with_retry (`request_id`, `candidate_index`, `retry_index`),
KEY request_candidates_request_id_idx (`request_id`),
KEY request_candidates_provider_id_idx (`provider_id`),
KEY request_candidates_endpoint_id_idx (`endpoint_id`),
KEY request_candidates_status_idx (`status`),
KEY request_candidates_created_at_idx (`created_at`),
KEY request_candidates_endpoint_status_created_idx (`endpoint_id`, `status`, `created_at`)
);
CREATE TABLE IF NOT EXISTS video_tasks (
`id` VARCHAR(64) NOT NULL,
`short_id` VARCHAR(32),
`request_id` VARCHAR(128) NOT NULL,
`user_id` VARCHAR(64),
`api_key_id` VARCHAR(64),
`username` VARCHAR(255),
`api_key_name` VARCHAR(255),
`external_task_id` VARCHAR(255),
`provider_id` VARCHAR(64),
`endpoint_id` VARCHAR(64),
`key_id` VARCHAR(64),
`client_api_format` VARCHAR(128),
`provider_api_format` VARCHAR(128),
`format_converted` TINYINT(1) NOT NULL DEFAULT 0,
`model` VARCHAR(255),
`prompt` LONGTEXT,
`original_request_body` JSON,
`converted_request_body` JSON,
`duration_seconds` INT,
`resolution` VARCHAR(64),
`aspect_ratio` VARCHAR(32),
`size` VARCHAR(64),
`status` VARCHAR(32) NOT NULL DEFAULT 'pending',
`progress_percent` INT NOT NULL DEFAULT 0,
`progress_message` LONGTEXT,
`retry_count` INT NOT NULL DEFAULT 0,
`max_retries` INT NOT NULL DEFAULT 3,
`poll_interval_seconds` INT NOT NULL DEFAULT 10,
`next_poll_at` BIGINT,
`poll_count` INT NOT NULL DEFAULT 0,
`max_poll_count` INT NOT NULL DEFAULT 360,
`created_at` BIGINT NOT NULL,
`submitted_at` BIGINT,
`completed_at` BIGINT,
`updated_at` BIGINT NOT NULL,
`error_code` VARCHAR(128),
`error_message` LONGTEXT,
`video_url` LONGTEXT,
`video_urls` JSON,
`thumbnail_url` LONGTEXT,
`video_size_bytes` BIGINT,
`video_expires_at` BIGINT,
`stored_video_path` VARCHAR(500),
`storage_provider` VARCHAR(50),
`remixed_from_task_id` VARCHAR(64),
`webhook_url` VARCHAR(500),
`webhook_sent` TINYINT(1) NOT NULL DEFAULT 0,
`webhook_sent_at` BIGINT,
`request_metadata` JSON,
`video_duration_seconds` DOUBLE,
PRIMARY KEY (`id`),
UNIQUE KEY video_tasks_short_id_key (`short_id`),
UNIQUE KEY video_tasks_request_id_key (`request_id`),
KEY video_tasks_external_id_idx (`external_task_id`),
KEY video_tasks_next_poll_idx (`next_poll_at`),
KEY video_tasks_user_status_idx (`user_id`, `status`),
KEY video_tasks_api_key_id_idx (`api_key_id`),
KEY video_tasks_provider_id_idx (`provider_id`),
KEY video_tasks_endpoint_id_idx (`endpoint_id`),
KEY video_tasks_key_id_idx (`key_id`)
);
CREATE TABLE IF NOT EXISTS provider_endpoints (
`id` VARCHAR(64) NOT NULL,
`provider_id` VARCHAR(64) NOT NULL,
`name` VARCHAR(255) NOT NULL,
`base_url` LONGTEXT NOT NULL,
`api_format` VARCHAR(128),
`api_family` VARCHAR(128),
`endpoint_kind` VARCHAR(128),
`enabled` TINYINT(1) NOT NULL DEFAULT 1,
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
`health_score` DOUBLE NOT NULL DEFAULT 1.0,
`weight` BIGINT NOT NULL DEFAULT 1,
`header_rules` JSON,
`body_rules` JSON,
`max_retries` INT,
`custom_path` LONGTEXT,
`metadata` JSON,
`config` JSON,
`format_acceptance_config` JSON,
`proxy` JSON,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
KEY provider_endpoints_provider_id_idx (`provider_id`)
);
CREATE TABLE IF NOT EXISTS provider_usage_tracking (
`id` VARCHAR(64) NOT NULL,
`provider_id` VARCHAR(64) NOT NULL,
`window_start` BIGINT NOT NULL,
`window_end` BIGINT NOT NULL,
`total_requests` INT NOT NULL DEFAULT 0,
`successful_requests` INT NOT NULL DEFAULT 0,
`failed_requests` INT NOT NULL DEFAULT 0,
`avg_response_time_ms` DOUBLE NOT NULL DEFAULT 0,
`total_response_time_ms` DOUBLE NOT NULL DEFAULT 0,
`total_cost_usd` DOUBLE NOT NULL DEFAULT 0,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
KEY provider_usage_tracking_provider_id_idx (`provider_id`),
KEY provider_usage_tracking_window_start_idx (`window_start`),
KEY idx_provider_window (`provider_id`, `window_start`),
KEY idx_window_time (`window_start`, `window_end`)
);
CREATE TABLE IF NOT EXISTS models (
`id` VARCHAR(64) NOT NULL,
`provider_id` VARCHAR(64) NOT NULL,
`global_model_id` VARCHAR(64),
`provider_model_name` VARCHAR(255) NOT NULL,
`global_model_name` VARCHAR(255),
`api_format` VARCHAR(128),
`enabled` TINYINT(1) NOT NULL DEFAULT 1,
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
`is_available` TINYINT(1) NOT NULL DEFAULT 1,
`price_per_request` DOUBLE,
`tiered_pricing` JSON,
`supports_vision` TINYINT(1),
`supports_function_calling` TINYINT(1),
`supports_streaming` TINYINT(1),
`supports_extended_thinking` TINYINT(1),
`supports_image_generation` TINYINT(1),
`provider_model_mappings` JSON,
`config` JSON,
`metadata` JSON,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
KEY models_provider_id_idx (`provider_id`)
);
CREATE TABLE IF NOT EXISTS global_models (
`id` VARCHAR(64) NOT NULL,
`name` VARCHAR(255) NOT NULL,
`display_name` VARCHAR(255),
`enabled` TINYINT(1) NOT NULL DEFAULT 1,
`is_active` TINYINT(1) NOT NULL DEFAULT 1,
`default_price_per_request` DOUBLE,
`default_tiered_pricing` JSON,
`supported_capabilities` JSON,
`usage_count` BIGINT NOT NULL DEFAULT 0,
`config` JSON,
`metadata` JSON,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY global_models_name_key (`name`)
);

View File

@@ -0,0 +1,80 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS system_configs (
`id` VARCHAR(64) NOT NULL,
`key` VARCHAR(255) NOT NULL,
`value` LONGTEXT NOT NULL,
`description` LONGTEXT,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY system_configs_key_key (`key`)
);
CREATE TABLE IF NOT EXISTS auth_modules (
`id` VARCHAR(64) NOT NULL,
`module_type` VARCHAR(128) NOT NULL,
`enabled` TINYINT(1) NOT NULL DEFAULT 1,
`config` JSON NOT NULL,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY auth_modules_module_type_key (`module_type`)
);
CREATE TABLE IF NOT EXISTS oauth_providers (
`provider_type` VARCHAR(64) NOT NULL,
`display_name` VARCHAR(255) NOT NULL,
`client_id` LONGTEXT NOT NULL,
`client_secret_encrypted` LONGTEXT,
`authorization_url_override` VARCHAR(500),
`token_url_override` VARCHAR(500),
`userinfo_url_override` VARCHAR(500),
`scopes` JSON,
`redirect_uri` VARCHAR(500) NOT NULL,
`frontend_callback_url` VARCHAR(500) NOT NULL,
`attribute_mapping` JSON,
`extra_config` JSON,
`is_enabled` TINYINT(1) NOT NULL DEFAULT 0,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`provider_type`)
);
CREATE TABLE IF NOT EXISTS ldap_configs (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`server_url` VARCHAR(255) NOT NULL,
`bind_dn` LONGTEXT NOT NULL,
`bind_password_encrypted` LONGTEXT,
`base_dn` LONGTEXT NOT NULL,
`user_search_filter` LONGTEXT NOT NULL DEFAULT '(uid={username})',
`username_attr` VARCHAR(50) NOT NULL DEFAULT 'uid',
`email_attr` VARCHAR(50) NOT NULL DEFAULT 'mail',
`display_name_attr` VARCHAR(50) NOT NULL DEFAULT 'cn',
`is_enabled` TINYINT(1) NOT NULL DEFAULT 0,
`is_exclusive` TINYINT(1) NOT NULL DEFAULT 0,
`use_starttls` TINYINT(1) NOT NULL DEFAULT 0,
`connect_timeout` INT NOT NULL DEFAULT 10,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE IF NOT EXISTS user_oauth_links (
`id` VARCHAR(64) NOT NULL,
`user_id` VARCHAR(64) NOT NULL,
`provider_type` VARCHAR(64) NOT NULL,
`provider_user_id` VARCHAR(255) NOT NULL,
`provider_username` VARCHAR(255),
`provider_email` VARCHAR(255),
`extra_data` JSON,
`linked_at` BIGINT NOT NULL,
`last_login_at` BIGINT,
PRIMARY KEY (`id`),
UNIQUE KEY uq_user_oauth_links_provider_user (`provider_type`, `provider_user_id`),
UNIQUE KEY uq_user_oauth_links_user_provider (`user_id`, `provider_type`),
KEY user_oauth_links_provider_type_idx (`provider_type`),
KEY user_oauth_links_user_id_idx (`user_id`)
);

View File

@@ -0,0 +1,45 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS proxy_nodes (
`id` VARCHAR(64) NOT NULL,
`name` VARCHAR(255) NOT NULL,
`ip` VARCHAR(512) NOT NULL,
`port` INT NOT NULL,
`region` VARCHAR(100),
`status` VARCHAR(32) NOT NULL DEFAULT 'online',
`registered_by` VARCHAR(64),
`last_heartbeat_at` BIGINT,
`heartbeat_interval` INT NOT NULL DEFAULT 30,
`active_connections` INT NOT NULL DEFAULT 0,
`total_requests` BIGINT NOT NULL DEFAULT 0,
`avg_latency_ms` DOUBLE,
`is_manual` TINYINT(1) NOT NULL DEFAULT 0,
`proxy_url` VARCHAR(500),
`proxy_username` VARCHAR(255),
`proxy_password` VARCHAR(500),
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
`remote_config` JSON,
`config_version` INT NOT NULL DEFAULT 0,
`hardware_info` JSON,
`estimated_max_concurrency` INT,
`tunnel_mode` TINYINT(1) NOT NULL DEFAULT 0,
`tunnel_connected` TINYINT(1) NOT NULL DEFAULT 0,
`tunnel_connected_at` BIGINT,
`failed_requests` BIGINT NOT NULL DEFAULT 0,
`dns_failures` BIGINT NOT NULL DEFAULT 0,
`stream_errors` BIGINT NOT NULL DEFAULT 0,
`proxy_metadata` JSON,
PRIMARY KEY (`id`)
);
CREATE TABLE IF NOT EXISTS proxy_node_events (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`node_id` VARCHAR(64) NOT NULL,
`event_type` VARCHAR(64) NOT NULL,
`detail` VARCHAR(500),
`created_at` BIGINT NOT NULL,
PRIMARY KEY (`id`)
);

View File

@@ -0,0 +1,195 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS wallets (
`id` VARCHAR(64) NOT NULL,
`user_id` VARCHAR(64),
`api_key_id` VARCHAR(64),
`balance` DOUBLE NOT NULL DEFAULT 0,
`gift_balance` DOUBLE NOT NULL DEFAULT 0,
`limit_mode` VARCHAR(64) NOT NULL DEFAULT 'finite',
`currency` VARCHAR(16) NOT NULL DEFAULT 'USD',
`status` VARCHAR(64) NOT NULL DEFAULT 'active',
`total_recharged` DOUBLE NOT NULL DEFAULT 0,
`total_consumed` DOUBLE NOT NULL DEFAULT 0,
`total_refunded` DOUBLE NOT NULL DEFAULT 0,
`total_adjusted` DOUBLE NOT NULL DEFAULT 0,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY wallets_user_id_key (`user_id`),
UNIQUE KEY wallets_api_key_id_key (`api_key_id`),
KEY wallets_api_key_id_idx (`api_key_id`),
KEY wallets_user_id_idx (`user_id`)
);
CREATE TABLE IF NOT EXISTS wallet_transactions (
`id` VARCHAR(64) NOT NULL,
`wallet_id` VARCHAR(64) NOT NULL,
`category` VARCHAR(64) NOT NULL,
`reason_code` VARCHAR(64) NOT NULL,
`amount` DOUBLE NOT NULL,
`balance_before` DOUBLE NOT NULL,
`balance_after` DOUBLE NOT NULL,
`recharge_balance_before` DOUBLE NOT NULL,
`recharge_balance_after` DOUBLE NOT NULL,
`gift_balance_before` DOUBLE NOT NULL,
`gift_balance_after` DOUBLE NOT NULL,
`link_type` VARCHAR(64),
`link_id` VARCHAR(128),
`operator_id` VARCHAR(64),
`description` LONGTEXT,
`created_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
KEY idx_wallet_tx_wallet_created (`wallet_id`, `created_at`),
KEY idx_wallet_tx_category_created (`category`, `created_at`),
KEY idx_wallet_tx_reason_created (`reason_code`, `created_at`),
KEY idx_wallet_tx_link (`link_type`, `link_id`),
KEY ix_wallet_transactions_operator_id (`operator_id`)
);
CREATE TABLE IF NOT EXISTS wallet_daily_usage_ledgers (
`id` VARCHAR(64) NOT NULL,
`wallet_id` VARCHAR(64) NOT NULL,
`billing_date` VARCHAR(16) NOT NULL,
`billing_timezone` VARCHAR(64) NOT NULL,
`total_cost_usd` DOUBLE NOT NULL DEFAULT 0,
`total_requests` BIGINT NOT NULL DEFAULT 0,
`input_tokens` BIGINT NOT NULL DEFAULT 0,
`output_tokens` BIGINT NOT NULL DEFAULT 0,
`cache_creation_tokens` BIGINT NOT NULL DEFAULT 0,
`cache_read_tokens` BIGINT NOT NULL DEFAULT 0,
`first_finalized_at` BIGINT,
`last_finalized_at` BIGINT,
`aggregated_at` BIGINT NOT NULL,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
KEY idx_wallet_daily_usage_wallet_date (`wallet_id`, `billing_timezone`, `billing_date`)
);
CREATE TABLE IF NOT EXISTS payment_orders (
`id` VARCHAR(64) NOT NULL,
`order_no` VARCHAR(128) NOT NULL,
`wallet_id` VARCHAR(64) NOT NULL,
`user_id` VARCHAR(64),
`amount_usd` DOUBLE NOT NULL,
`pay_amount` DOUBLE,
`pay_currency` VARCHAR(16),
`exchange_rate` DOUBLE,
`refunded_amount_usd` DOUBLE NOT NULL DEFAULT 0,
`refundable_amount_usd` DOUBLE NOT NULL DEFAULT 0,
`payment_method` VARCHAR(64) NOT NULL,
`gateway_order_id` VARCHAR(128),
`gateway_response` JSON,
`status` VARCHAR(64) NOT NULL DEFAULT 'pending',
`created_at` BIGINT NOT NULL,
`paid_at` BIGINT,
`credited_at` BIGINT,
`expires_at` BIGINT,
PRIMARY KEY (`id`),
UNIQUE KEY uq_payment_orders_order_no (`order_no`),
KEY idx_payment_orders_wallet_created (`wallet_id`, `created_at`),
KEY idx_payment_orders_user_created (`user_id`, `created_at`),
KEY idx_payment_orders_status (`status`),
KEY idx_payment_orders_gateway_order_id (`gateway_order_id`)
);
CREATE TABLE IF NOT EXISTS payment_callbacks (
`id` VARCHAR(64) NOT NULL,
`payment_order_id` VARCHAR(64),
`payment_method` VARCHAR(64) NOT NULL,
`callback_key` VARCHAR(128) NOT NULL,
`order_no` VARCHAR(128),
`gateway_order_id` VARCHAR(128),
`payload_hash` VARCHAR(128),
`signature_valid` TINYINT(1) NOT NULL DEFAULT 0,
`status` VARCHAR(64) NOT NULL DEFAULT 'received',
`payload` JSON,
`error_message` LONGTEXT,
`created_at` BIGINT NOT NULL,
`processed_at` BIGINT,
PRIMARY KEY (`id`),
UNIQUE KEY uq_payment_callbacks_callback_key (`callback_key`),
KEY idx_payment_callbacks_order (`order_no`),
KEY idx_payment_callbacks_gateway_order (`gateway_order_id`),
KEY idx_payment_callbacks_created (`created_at`),
KEY ix_payment_callbacks_payment_order_id (`payment_order_id`)
);
CREATE TABLE IF NOT EXISTS refund_requests (
`id` VARCHAR(64) NOT NULL,
`refund_no` VARCHAR(128) NOT NULL,
`wallet_id` VARCHAR(64) NOT NULL,
`user_id` VARCHAR(64),
`payment_order_id` VARCHAR(64),
`source_type` VARCHAR(64) NOT NULL,
`source_id` VARCHAR(128),
`refund_mode` VARCHAR(64) NOT NULL,
`amount_usd` DOUBLE NOT NULL,
`status` VARCHAR(64) NOT NULL DEFAULT 'pending_approval',
`reason` LONGTEXT,
`requested_by` VARCHAR(64),
`approved_by` VARCHAR(64),
`processed_by` VARCHAR(64),
`gateway_refund_id` VARCHAR(128),
`payout_method` VARCHAR(64),
`payout_reference` VARCHAR(255),
`payout_proof` JSON,
`failure_reason` LONGTEXT,
`idempotency_key` VARCHAR(128),
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
`processed_at` BIGINT,
`completed_at` BIGINT,
PRIMARY KEY (`id`),
UNIQUE KEY uq_refund_requests_refund_no (`refund_no`),
UNIQUE KEY uq_refund_requests_idempotency_key (`idempotency_key`),
KEY idx_refund_wallet_created (`wallet_id`, `created_at`),
KEY idx_refund_user_created (`user_id`, `created_at`),
KEY idx_refund_status (`status`),
KEY ix_refund_requests_payment_order_id (`payment_order_id`),
KEY ix_refund_requests_requested_by (`requested_by`),
KEY ix_refund_requests_approved_by (`approved_by`),
KEY ix_refund_requests_processed_by (`processed_by`)
);
CREATE TABLE IF NOT EXISTS redeem_code_batches (
`id` VARCHAR(64) NOT NULL,
`name` VARCHAR(255) NOT NULL,
`amount_usd` DOUBLE NOT NULL,
`currency` VARCHAR(16) NOT NULL DEFAULT 'USD',
`balance_bucket` VARCHAR(64) NOT NULL DEFAULT 'gift',
`total_count` INT NOT NULL,
`status` VARCHAR(64) NOT NULL DEFAULT 'active',
`description` LONGTEXT,
`created_by` VARCHAR(64),
`expires_at` BIGINT,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
KEY idx_redeem_code_batches_status (`status`, `created_at`)
);
CREATE TABLE IF NOT EXISTS redeem_codes (
`id` VARCHAR(64) NOT NULL,
`batch_id` VARCHAR(64) NOT NULL,
`code_hash` VARCHAR(128) NOT NULL,
`code_prefix` VARCHAR(16) NOT NULL,
`code_suffix` VARCHAR(16) NOT NULL,
`status` VARCHAR(64) NOT NULL DEFAULT 'active',
`redeemed_by_user_id` VARCHAR(64),
`redeemed_wallet_id` VARCHAR(64),
`redeemed_payment_order_id` VARCHAR(64),
`redeemed_at` BIGINT,
`disabled_by` VARCHAR(64),
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY uq_redeem_codes_code_hash (`code_hash`),
KEY idx_redeem_codes_batch_created (`batch_id`, `created_at`),
KEY idx_redeem_codes_status (`status`, `updated_at`),
KEY idx_redeem_codes_redeemed_user (`redeemed_by_user_id`, `redeemed_at`),
KEY idx_redeem_codes_redeemed_order (`redeemed_payment_order_id`)
);

View File

@@ -0,0 +1,131 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS `usage` (
`request_id` VARCHAR(128) NOT NULL,
`id` VARCHAR(128),
`user_id` VARCHAR(64),
`api_key_id` VARCHAR(64),
`provider_name` VARCHAR(255) NOT NULL DEFAULT 'unknown',
`model` VARCHAR(255) NOT NULL DEFAULT 'unknown',
`target_model` VARCHAR(255),
`provider_id` VARCHAR(64),
`provider_endpoint_id` VARCHAR(64),
`provider_api_key_id` VARCHAR(64),
`request_type` VARCHAR(64),
`api_format` VARCHAR(64),
`api_family` VARCHAR(64),
`endpoint_kind` VARCHAR(64),
`endpoint_api_format` VARCHAR(64),
`provider_api_family` VARCHAR(64),
`provider_endpoint_kind` VARCHAR(64),
`has_format_conversion` TINYINT(1) NOT NULL DEFAULT 0,
`is_stream` TINYINT(1) NOT NULL DEFAULT 0,
`input_tokens` BIGINT NOT NULL DEFAULT 0,
`output_tokens` BIGINT NOT NULL DEFAULT 0,
`input_output_total_tokens` BIGINT NOT NULL DEFAULT 0,
`total_tokens` BIGINT NOT NULL DEFAULT 0,
`cache_creation_input_tokens` BIGINT NOT NULL DEFAULT 0,
`cache_creation_input_tokens_5m` BIGINT NOT NULL DEFAULT 0,
`cache_creation_input_tokens_1h` BIGINT NOT NULL DEFAULT 0,
`cache_creation_ephemeral_5m_input_tokens` BIGINT NOT NULL DEFAULT 0,
`cache_creation_ephemeral_1h_input_tokens` BIGINT NOT NULL DEFAULT 0,
`cache_read_input_tokens` BIGINT NOT NULL DEFAULT 0,
`input_context_tokens` BIGINT NOT NULL DEFAULT 0,
`input_cost_usd` DOUBLE NOT NULL DEFAULT 0,
`output_cost_usd` DOUBLE NOT NULL DEFAULT 0,
`cache_cost_usd` DOUBLE NOT NULL DEFAULT 0,
`cache_creation_cost_usd` DOUBLE NOT NULL DEFAULT 0,
`cache_creation_cost_usd_5m` DOUBLE NOT NULL DEFAULT 0,
`cache_creation_cost_usd_1h` DOUBLE NOT NULL DEFAULT 0,
`cache_read_cost_usd` DOUBLE NOT NULL DEFAULT 0,
`request_cost_usd` DOUBLE NOT NULL DEFAULT 0,
`actual_input_cost_usd` DOUBLE NOT NULL DEFAULT 0,
`actual_output_cost_usd` DOUBLE NOT NULL DEFAULT 0,
`actual_cache_cost_usd` DOUBLE NOT NULL DEFAULT 0,
`actual_cache_creation_cost_usd` DOUBLE NOT NULL DEFAULT 0,
`actual_cache_creation_cost_usd_5m` DOUBLE NOT NULL DEFAULT 0,
`actual_cache_creation_cost_usd_1h` DOUBLE NOT NULL DEFAULT 0,
`actual_cache_read_cost_usd` DOUBLE NOT NULL DEFAULT 0,
`actual_request_cost_usd` DOUBLE NOT NULL DEFAULT 0,
`rate_multiplier` DOUBLE NOT NULL DEFAULT 1,
`input_price_per_1m` DOUBLE,
`output_price_per_1m` DOUBLE,
`cache_creation_price_per_1m` DOUBLE,
`cache_creation_price_per_1m_5m` DOUBLE,
`cache_creation_price_per_1m_1h` DOUBLE,
`cache_read_price_per_1m` DOUBLE,
`price_per_request` DOUBLE,
`status_code` INT,
`error_message` LONGTEXT,
`error_category` VARCHAR(255),
`response_time_ms` BIGINT,
`first_byte_time_ms` BIGINT,
`wallet_id` VARCHAR(64),
`status` VARCHAR(64) NOT NULL DEFAULT 'completed',
`billing_status` VARCHAR(64) NOT NULL DEFAULT 'pending',
`total_cost_usd` DOUBLE NOT NULL DEFAULT 0,
`actual_total_cost_usd` DOUBLE NOT NULL DEFAULT 0,
`request_headers` JSON,
`request_body` JSON,
`provider_request_headers` JSON,
`provider_request_body` JSON,
`response_headers` JSON,
`response_body` JSON,
`client_response_headers` JSON,
`client_response_body` JSON,
`request_body_compressed` LONGBLOB,
`provider_request_body_compressed` LONGBLOB,
`response_body_compressed` LONGBLOB,
`client_response_body_compressed` LONGBLOB,
`request_metadata` JSON,
`created_at` BIGINT,
`candidate_id` VARCHAR(128),
`candidate_index` BIGINT,
`key_name` VARCHAR(255),
`username` VARCHAR(255),
`api_key_name` VARCHAR(255),
`planner_kind` VARCHAR(64),
`route_family` VARCHAR(128),
`route_kind` VARCHAR(128),
`execution_path` VARCHAR(128),
`local_execution_runtime_miss_reason` VARCHAR(255),
`wallet_balance_before` DOUBLE,
`wallet_balance_after` DOUBLE,
`wallet_recharge_balance_before` DOUBLE,
`wallet_recharge_balance_after` DOUBLE,
`wallet_gift_balance_before` DOUBLE,
`wallet_gift_balance_after` DOUBLE,
`finalized_at` BIGINT,
`created_at_unix_ms` BIGINT NOT NULL DEFAULT 0,
`updated_at_unix_secs` BIGINT NOT NULL DEFAULT 0,
PRIMARY KEY (`request_id`),
KEY usage_api_key_id_idx (`api_key_id`),
KEY usage_billing_status_idx (`billing_status`),
KEY usage_created_at_idx (`created_at_unix_ms`),
KEY usage_provider_api_key_id_idx (`provider_api_key_id`),
KEY usage_provider_id_idx (`provider_id`),
KEY usage_request_id_idx (`request_id`),
KEY usage_user_id_idx (`user_id`),
KEY usage_wallet_id_idx (`wallet_id`)
);
CREATE TABLE IF NOT EXISTS usage_settlement_snapshots (
`request_id` VARCHAR(128) NOT NULL,
`billing_status` VARCHAR(64) NOT NULL,
`wallet_id` VARCHAR(64),
`wallet_balance_before` DOUBLE,
`wallet_balance_after` DOUBLE,
`wallet_recharge_balance_before` DOUBLE,
`wallet_recharge_balance_after` DOUBLE,
`wallet_gift_balance_before` DOUBLE,
`wallet_gift_balance_after` DOUBLE,
`provider_monthly_used_usd` DOUBLE,
`finalized_at` BIGINT,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`request_id`),
KEY usage_settlement_snapshots_billing_status_idx (`billing_status`),
KEY usage_settlement_snapshots_wallet_id_idx (`wallet_id`)
);

View File

@@ -0,0 +1,236 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS stats_hourly (
`id` VARCHAR(64) NOT NULL,
`hour_utc` BIGINT NOT NULL,
`total_requests` BIGINT NOT NULL DEFAULT 0,
`success_requests` BIGINT NOT NULL DEFAULT 0,
`error_requests` BIGINT NOT NULL DEFAULT 0,
`input_tokens` BIGINT NOT NULL DEFAULT 0,
`output_tokens` BIGINT NOT NULL DEFAULT 0,
`cache_creation_tokens` BIGINT NOT NULL DEFAULT 0,
`cache_read_tokens` BIGINT NOT NULL DEFAULT 0,
`total_cost` DOUBLE NOT NULL DEFAULT 0,
`actual_total_cost` DOUBLE NOT NULL DEFAULT 0,
`avg_response_time_ms` DOUBLE NOT NULL DEFAULT 0,
`is_complete` TINYINT(1) NOT NULL DEFAULT 0,
`aggregated_at` BIGINT,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY uq_stats_hourly_hour (`hour_utc`)
);
CREATE TABLE IF NOT EXISTS stats_summary (
`id` VARCHAR(64) NOT NULL,
`cutoff_date` BIGINT NOT NULL,
`all_time_requests` BIGINT NOT NULL DEFAULT 0,
`all_time_success_requests` BIGINT NOT NULL DEFAULT 0,
`all_time_error_requests` BIGINT NOT NULL DEFAULT 0,
`all_time_input_tokens` BIGINT NOT NULL DEFAULT 0,
`all_time_output_tokens` BIGINT NOT NULL DEFAULT 0,
`all_time_cache_creation_tokens` BIGINT NOT NULL DEFAULT 0,
`all_time_cache_read_tokens` BIGINT NOT NULL DEFAULT 0,
`all_time_cost` DOUBLE NOT NULL DEFAULT 0,
`all_time_actual_cost` DOUBLE NOT NULL DEFAULT 0,
`total_users` BIGINT NOT NULL DEFAULT 0,
`active_users` BIGINT NOT NULL DEFAULT 0,
`total_api_keys` BIGINT NOT NULL DEFAULT 0,
`active_api_keys` BIGINT NOT NULL DEFAULT 0,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE IF NOT EXISTS stats_hourly_user (
`id` VARCHAR(64) NOT NULL,
`hour_utc` BIGINT NOT NULL,
`user_id` VARCHAR(64) NOT NULL,
`total_requests` BIGINT NOT NULL DEFAULT 0,
`success_requests` BIGINT NOT NULL DEFAULT 0,
`error_requests` BIGINT NOT NULL DEFAULT 0,
`input_tokens` BIGINT NOT NULL DEFAULT 0,
`output_tokens` BIGINT NOT NULL DEFAULT 0,
`total_cost` DOUBLE NOT NULL DEFAULT 0,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY uq_stats_hourly_user (`hour_utc`, `user_id`)
);
CREATE TABLE IF NOT EXISTS stats_hourly_user_model (
`id` VARCHAR(64) NOT NULL,
`hour_utc` BIGINT NOT NULL,
`user_id` VARCHAR(64) NOT NULL,
`model` VARCHAR(255) NOT NULL,
`total_requests` BIGINT NOT NULL DEFAULT 0,
`input_tokens` BIGINT NOT NULL DEFAULT 0,
`output_tokens` BIGINT NOT NULL DEFAULT 0,
`total_cost` DOUBLE NOT NULL DEFAULT 0,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY uq_stats_hourly_user_model (`hour_utc`, `user_id`, `model`)
);
CREATE TABLE IF NOT EXISTS user_model_usage_counts (
`id` VARCHAR(64) NOT NULL,
`user_id` VARCHAR(64) NOT NULL,
`model` VARCHAR(255) NOT NULL,
`usage_count` BIGINT NOT NULL DEFAULT 0,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY uq_user_model_usage_count (`user_id`, `model`),
KEY idx_user_model_usage_user (`user_id`),
KEY idx_user_model_usage_model (`model`)
);
CREATE TABLE IF NOT EXISTS stats_hourly_model (
`id` VARCHAR(64) NOT NULL,
`hour_utc` BIGINT NOT NULL,
`model` VARCHAR(255) NOT NULL,
`total_requests` BIGINT NOT NULL DEFAULT 0,
`input_tokens` BIGINT NOT NULL DEFAULT 0,
`output_tokens` BIGINT NOT NULL DEFAULT 0,
`total_cost` DOUBLE NOT NULL DEFAULT 0,
`avg_response_time_ms` DOUBLE NOT NULL DEFAULT 0,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY uq_stats_hourly_model (`hour_utc`, `model`)
);
CREATE TABLE IF NOT EXISTS stats_hourly_provider (
`id` VARCHAR(64) NOT NULL,
`hour_utc` BIGINT NOT NULL,
`provider_name` VARCHAR(255) NOT NULL,
`total_requests` BIGINT NOT NULL DEFAULT 0,
`input_tokens` BIGINT NOT NULL DEFAULT 0,
`output_tokens` BIGINT NOT NULL DEFAULT 0,
`total_cost` DOUBLE NOT NULL DEFAULT 0,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY uq_stats_hourly_provider (`hour_utc`, `provider_name`)
);
CREATE TABLE IF NOT EXISTS stats_daily (
`id` VARCHAR(64) NOT NULL,
`date` BIGINT NOT NULL,
`total_requests` BIGINT NOT NULL DEFAULT 0,
`success_requests` BIGINT NOT NULL DEFAULT 0,
`error_requests` BIGINT NOT NULL DEFAULT 0,
`input_tokens` BIGINT NOT NULL DEFAULT 0,
`output_tokens` BIGINT NOT NULL DEFAULT 0,
`cache_creation_tokens` BIGINT NOT NULL DEFAULT 0,
`cache_read_tokens` BIGINT NOT NULL DEFAULT 0,
`total_cost` DOUBLE NOT NULL DEFAULT 0,
`actual_total_cost` DOUBLE NOT NULL DEFAULT 0,
`input_cost` DOUBLE NOT NULL DEFAULT 0,
`output_cost` DOUBLE NOT NULL DEFAULT 0,
`cache_creation_cost` DOUBLE NOT NULL DEFAULT 0,
`cache_read_cost` DOUBLE NOT NULL DEFAULT 0,
`avg_response_time_ms` DOUBLE NOT NULL DEFAULT 0,
`fallback_count` BIGINT NOT NULL DEFAULT 0,
`unique_models` BIGINT NOT NULL DEFAULT 0,
`unique_providers` BIGINT NOT NULL DEFAULT 0,
`is_complete` TINYINT(1) NOT NULL DEFAULT 0,
`aggregated_at` BIGINT,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
`p50_response_time_ms` BIGINT,
`p90_response_time_ms` BIGINT,
`p99_response_time_ms` BIGINT,
`p50_first_byte_time_ms` BIGINT,
`p90_first_byte_time_ms` BIGINT,
`p99_first_byte_time_ms` BIGINT,
PRIMARY KEY (`id`),
UNIQUE KEY uq_stats_daily_date (`date`)
);
CREATE TABLE IF NOT EXISTS stats_daily_model (
`id` VARCHAR(64) NOT NULL,
`date` BIGINT NOT NULL,
`model` VARCHAR(255) NOT NULL,
`total_requests` BIGINT NOT NULL DEFAULT 0,
`input_tokens` BIGINT NOT NULL DEFAULT 0,
`output_tokens` BIGINT NOT NULL DEFAULT 0,
`cache_creation_tokens` BIGINT NOT NULL DEFAULT 0,
`cache_read_tokens` BIGINT NOT NULL DEFAULT 0,
`total_cost` DOUBLE NOT NULL DEFAULT 0,
`avg_response_time_ms` DOUBLE NOT NULL DEFAULT 0,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY uq_stats_daily_model (`date`, `model`)
);
CREATE TABLE IF NOT EXISTS stats_daily_provider (
`id` VARCHAR(64) NOT NULL,
`date` BIGINT NOT NULL,
`provider_name` VARCHAR(255) NOT NULL,
`total_requests` BIGINT NOT NULL DEFAULT 0,
`input_tokens` BIGINT NOT NULL DEFAULT 0,
`output_tokens` BIGINT NOT NULL DEFAULT 0,
`cache_creation_tokens` BIGINT NOT NULL DEFAULT 0,
`cache_read_tokens` BIGINT NOT NULL DEFAULT 0,
`total_cost` DOUBLE NOT NULL DEFAULT 0,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY uq_stats_daily_provider (`date`, `provider_name`)
);
CREATE TABLE IF NOT EXISTS stats_daily_api_key (
`id` VARCHAR(64) NOT NULL,
`api_key_id` VARCHAR(64) NOT NULL,
`date` BIGINT NOT NULL,
`total_requests` BIGINT NOT NULL DEFAULT 0,
`success_requests` BIGINT NOT NULL DEFAULT 0,
`error_requests` BIGINT NOT NULL DEFAULT 0,
`input_tokens` BIGINT NOT NULL DEFAULT 0,
`output_tokens` BIGINT NOT NULL DEFAULT 0,
`cache_creation_tokens` BIGINT NOT NULL DEFAULT 0,
`cache_read_tokens` BIGINT NOT NULL DEFAULT 0,
`total_cost` DOUBLE NOT NULL DEFAULT 0,
`api_key_name` VARCHAR(255),
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY uq_stats_daily_api_key (`date`, `api_key_id`)
);
CREATE TABLE IF NOT EXISTS stats_daily_error (
`id` VARCHAR(64) NOT NULL,
`date` BIGINT NOT NULL,
`error_category` VARCHAR(255) NOT NULL,
`provider_name` VARCHAR(255),
`model` VARCHAR(255),
`count` BIGINT NOT NULL DEFAULT 0,
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY uq_stats_daily_error (`date`, `error_category`, `provider_name`, `model`)
);
CREATE TABLE IF NOT EXISTS stats_user_daily (
`id` VARCHAR(64) NOT NULL,
`user_id` VARCHAR(64) NOT NULL,
`date` BIGINT NOT NULL,
`total_requests` BIGINT NOT NULL DEFAULT 0,
`success_requests` BIGINT NOT NULL DEFAULT 0,
`error_requests` BIGINT NOT NULL DEFAULT 0,
`input_tokens` BIGINT NOT NULL DEFAULT 0,
`output_tokens` BIGINT NOT NULL DEFAULT 0,
`cache_creation_tokens` BIGINT NOT NULL DEFAULT 0,
`cache_read_tokens` BIGINT NOT NULL DEFAULT 0,
`total_cost` DOUBLE NOT NULL DEFAULT 0,
`username` VARCHAR(255),
`created_at` BIGINT NOT NULL,
`updated_at` BIGINT NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY uq_stats_user_daily (`date`, `user_id`)
);

View File

@@ -0,0 +1,10 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
001_identity.sql
002_provider_catalog.sql
003_auth_config.sql
004_proxy_nodes.sql
005_wallet_billing.sql
006_usage.sql
007_stats.sql

View File

@@ -0,0 +1,188 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS public.users (
id character varying(64) NOT NULL,
external_id character varying(255),
email character varying(320),
username character varying(255),
password_hash character varying(255),
role character varying(64),
auth_source character varying(64) DEFAULT 'local' NOT NULL,
email_verified boolean DEFAULT false NOT NULL,
is_active boolean DEFAULT true NOT NULL,
is_deleted boolean DEFAULT false NOT NULL,
allowed_models jsonb,
allowed_providers jsonb,
allowed_api_formats jsonb,
model_capability_settings jsonb,
rate_limit integer,
metadata jsonb,
created_at bigint NOT NULL,
updated_at bigint NOT NULL,
last_login_at bigint,
ldap_dn character varying(1024),
ldap_username character varying(255)
);
ALTER TABLE ONLY public.users ADD CONSTRAINT users_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.users ADD CONSTRAINT users_email_key UNIQUE (email);
ALTER TABLE ONLY public.users ADD CONSTRAINT users_username_key UNIQUE (username);
CREATE TABLE IF NOT EXISTS public.api_keys (
id character varying(64) NOT NULL,
user_id character varying(64) NOT NULL,
key_hash character varying(255) NOT NULL,
key_encrypted text,
name character varying(255),
key_prefix character varying(64),
status character varying(64) DEFAULT 'active' NOT NULL,
allowed_models jsonb,
allowed_providers jsonb,
allowed_api_formats jsonb,
rate_limit integer DEFAULT 100,
concurrent_limit integer,
force_capabilities jsonb,
is_active boolean DEFAULT true NOT NULL,
is_locked boolean DEFAULT false NOT NULL,
is_standalone boolean DEFAULT false NOT NULL,
auto_delete_on_expiry boolean DEFAULT false NOT NULL,
total_requests bigint DEFAULT 0 NOT NULL,
total_tokens bigint DEFAULT 0 NOT NULL,
total_cost_usd double precision DEFAULT 0 NOT NULL,
metadata jsonb,
expires_at bigint,
last_used_at bigint,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.api_keys ADD CONSTRAINT api_keys_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.api_keys ADD CONSTRAINT api_keys_key_hash_key UNIQUE (key_hash);
CREATE INDEX IF NOT EXISTS api_keys_user_id_idx ON public.api_keys USING btree (user_id);
CREATE TABLE IF NOT EXISTS public.audit_logs (
id character varying(64) NOT NULL,
event_type character varying(64) NOT NULL,
user_id character varying(64),
api_key_id character varying(64),
description text NOT NULL,
ip_address character varying(64),
user_agent character varying(512),
request_id character varying(128),
event_metadata jsonb,
status_code integer,
error_message text,
created_at bigint NOT NULL
);
ALTER TABLE ONLY public.audit_logs ADD CONSTRAINT audit_logs_pkey PRIMARY KEY (id);
CREATE INDEX IF NOT EXISTS audit_logs_created_at_idx ON public.audit_logs USING btree (created_at);
CREATE INDEX IF NOT EXISTS audit_logs_event_type_idx ON public.audit_logs USING btree (event_type);
CREATE INDEX IF NOT EXISTS audit_logs_request_id_idx ON public.audit_logs USING btree (request_id);
CREATE INDEX IF NOT EXISTS audit_logs_user_id_idx ON public.audit_logs USING btree (user_id);
CREATE TABLE IF NOT EXISTS public.announcements (
id character varying(64) NOT NULL,
title character varying(200) NOT NULL,
content text NOT NULL,
type character varying(32) DEFAULT 'info' NOT NULL,
priority integer DEFAULT 0 NOT NULL,
author_id character varying(64),
is_active boolean DEFAULT true NOT NULL,
is_pinned boolean DEFAULT false NOT NULL,
start_time bigint,
end_time bigint,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.announcements ADD CONSTRAINT announcements_pkey PRIMARY KEY (id);
CREATE INDEX IF NOT EXISTS announcements_author_id_idx ON public.announcements USING btree (author_id);
CREATE INDEX IF NOT EXISTS announcements_created_at_idx ON public.announcements USING btree (created_at);
CREATE INDEX IF NOT EXISTS announcements_is_active_idx ON public.announcements USING btree (is_active);
CREATE TABLE IF NOT EXISTS public.announcement_reads (
id character varying(64) NOT NULL,
user_id character varying(64) NOT NULL,
announcement_id character varying(64) NOT NULL,
read_at bigint NOT NULL
);
ALTER TABLE ONLY public.announcement_reads ADD CONSTRAINT announcement_reads_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.announcement_reads ADD CONSTRAINT uq_user_announcement UNIQUE (user_id, announcement_id);
CREATE INDEX IF NOT EXISTS announcement_reads_announcement_id_idx ON public.announcement_reads USING btree (announcement_id);
CREATE INDEX IF NOT EXISTS announcement_reads_user_id_idx ON public.announcement_reads USING btree (user_id);
CREATE TABLE IF NOT EXISTS public.management_tokens (
id character varying(64) NOT NULL,
user_id character varying(64) NOT NULL,
name character varying(255) NOT NULL,
description text,
token_hash character varying(255) NOT NULL,
token_prefix character varying(64),
allowed_ips jsonb,
expires_at bigint,
last_used_at bigint,
last_used_ip character varying(255),
usage_count bigint DEFAULT 0 NOT NULL,
is_active boolean DEFAULT true NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.management_tokens ADD CONSTRAINT management_tokens_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.management_tokens ADD CONSTRAINT management_tokens_token_hash_key UNIQUE (token_hash);
ALTER TABLE ONLY public.management_tokens ADD CONSTRAINT uq_management_tokens_user_name UNIQUE (user_id, name);
CREATE INDEX IF NOT EXISTS management_tokens_user_id_idx ON public.management_tokens USING btree (user_id);
CREATE TABLE IF NOT EXISTS public.user_preferences (
id character varying(64) NOT NULL,
user_id character varying(64) NOT NULL,
avatar_url character varying(500),
bio text,
default_provider_id character varying(64),
theme character varying(20) DEFAULT 'light' NOT NULL,
language character varying(10) DEFAULT 'zh-CN' NOT NULL,
timezone character varying(50) DEFAULT 'Asia/Shanghai' NOT NULL,
email_notifications boolean DEFAULT true NOT NULL,
usage_alerts boolean DEFAULT true NOT NULL,
announcement_notifications boolean DEFAULT true NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.user_preferences ADD CONSTRAINT user_preferences_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.user_preferences ADD CONSTRAINT user_preferences_user_id_key UNIQUE (user_id);
CREATE INDEX IF NOT EXISTS user_preferences_default_provider_id_idx ON public.user_preferences USING btree (default_provider_id);
CREATE INDEX IF NOT EXISTS user_preferences_user_id_idx ON public.user_preferences USING btree (user_id);
CREATE TABLE IF NOT EXISTS public.user_sessions (
id character varying(64) NOT NULL,
user_id character varying(64) NOT NULL,
client_device_id character varying(128) NOT NULL,
device_label character varying(120),
device_type character varying(20) DEFAULT 'unknown' NOT NULL,
browser_name character varying(50),
browser_version character varying(50),
os_name character varying(50),
os_version character varying(50),
device_model character varying(100),
ip_address character varying(45),
user_agent character varying(1000),
client_hints jsonb,
refresh_token_hash character varying(64) NOT NULL,
prev_refresh_token_hash character varying(64),
rotated_at bigint,
last_seen_at bigint NOT NULL,
expires_at bigint NOT NULL,
revoked_at bigint,
revoke_reason character varying(100),
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.user_sessions ADD CONSTRAINT user_sessions_pkey PRIMARY KEY (id);
CREATE INDEX IF NOT EXISTS user_sessions_user_active_idx ON public.user_sessions USING btree (user_id, revoked_at, expires_at);
CREATE INDEX IF NOT EXISTS user_sessions_user_device_idx ON public.user_sessions USING btree (user_id, client_device_id);

View File

@@ -0,0 +1,366 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS public.billing_rules (
id character varying(64) NOT NULL,
global_model_id character varying(64),
model_id character varying(64),
name character varying(255) NOT NULL,
task_type character varying(64) DEFAULT 'chat' NOT NULL,
expression text NOT NULL,
variables jsonb NOT NULL,
dimension_mappings jsonb NOT NULL,
is_enabled boolean DEFAULT true NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.billing_rules ADD CONSTRAINT billing_rules_pkey PRIMARY KEY (id);
CREATE INDEX IF NOT EXISTS billing_rules_global_model_task_idx ON public.billing_rules USING btree (global_model_id, task_type, is_enabled);
CREATE INDEX IF NOT EXISTS billing_rules_model_task_idx ON public.billing_rules USING btree (model_id, task_type, is_enabled);
CREATE TABLE IF NOT EXISTS public.dimension_collectors (
id character varying(64) NOT NULL,
api_format character varying(64) NOT NULL,
task_type character varying(64) NOT NULL,
dimension_name character varying(128) NOT NULL,
source_type character varying(64) NOT NULL,
source_path character varying(255),
value_type character varying(64) DEFAULT 'float' NOT NULL,
transform_expression text,
default_value character varying(255),
priority integer DEFAULT 0 NOT NULL,
is_enabled boolean DEFAULT true NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.dimension_collectors ADD CONSTRAINT dimension_collectors_pkey PRIMARY KEY (id);
CREATE INDEX IF NOT EXISTS dimension_collectors_enabled_idx ON public.dimension_collectors USING btree (api_format, task_type, dimension_name, priority, is_enabled);
CREATE TABLE IF NOT EXISTS public.providers (
id character varying(64) NOT NULL,
name character varying(255) NOT NULL,
description text,
website character varying(500),
provider_type character varying(64) NOT NULL,
billing_type character varying(64),
monthly_quota_usd double precision,
monthly_used_usd double precision,
quota_reset_day integer,
quota_last_reset_at bigint,
quota_expires_at bigint,
enabled boolean DEFAULT true NOT NULL,
is_active boolean DEFAULT true NOT NULL,
priority bigint DEFAULT 0 NOT NULL,
provider_priority integer DEFAULT 100 NOT NULL,
keep_priority_on_conversion boolean DEFAULT false NOT NULL,
enable_format_conversion boolean DEFAULT true NOT NULL,
concurrent_limit integer,
max_retries integer,
proxy jsonb,
request_timeout double precision,
stream_first_byte_timeout double precision,
config jsonb,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.providers ADD CONSTRAINT providers_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.providers ADD CONSTRAINT providers_name_key UNIQUE (name);
CREATE TABLE IF NOT EXISTS public.provider_api_keys (
id character varying(64) NOT NULL,
provider_id character varying(64) NOT NULL,
name character varying(255) NOT NULL,
api_key text,
encrypted_key text,
auth_type character varying(32) DEFAULT 'api_key' NOT NULL,
auth_config jsonb,
note text,
internal_priority integer DEFAULT 50 NOT NULL,
capabilities jsonb,
api_formats jsonb,
auth_type_by_format jsonb,
allow_auth_channel_mismatch_formats jsonb,
rate_multipliers jsonb,
global_priority_by_format jsonb,
allowed_models jsonb,
expires_at bigint,
cache_ttl_minutes integer DEFAULT 5 NOT NULL,
max_probe_interval_minutes integer DEFAULT 32 NOT NULL,
proxy jsonb,
fingerprint jsonb,
concurrent_limit integer,
learned_rpm_limit integer,
concurrent_429_count integer DEFAULT 0 NOT NULL,
rpm_429_count integer DEFAULT 0 NOT NULL,
last_429_at bigint,
last_429_type character varying(64),
adjustment_history jsonb,
utilization_samples jsonb,
last_probe_increase_at bigint,
last_rpm_peak integer,
request_count bigint DEFAULT 0 NOT NULL,
total_tokens bigint DEFAULT 0 NOT NULL,
total_cost_usd double precision DEFAULT 0 NOT NULL,
success_count bigint DEFAULT 0 NOT NULL,
error_count bigint DEFAULT 0 NOT NULL,
total_response_time_ms bigint DEFAULT 0 NOT NULL,
last_used_at bigint,
last_error_at bigint,
last_error_msg text,
auto_fetch_models boolean DEFAULT false NOT NULL,
last_models_fetch_at bigint,
last_models_fetch_error text,
locked_models jsonb,
model_include_patterns jsonb,
model_exclude_patterns jsonb,
upstream_metadata jsonb,
oauth_invalid_at bigint,
oauth_invalid_reason character varying(255),
status_snapshot jsonb,
health_by_format jsonb,
circuit_breaker_by_format jsonb,
status character varying(64) DEFAULT 'active' NOT NULL,
is_active boolean DEFAULT true NOT NULL,
weight bigint DEFAULT 1 NOT NULL,
rpm_limit bigint,
metadata jsonb,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.provider_api_keys ADD CONSTRAINT provider_api_keys_pkey PRIMARY KEY (id);
CREATE INDEX IF NOT EXISTS provider_api_keys_provider_id_idx ON public.provider_api_keys USING btree (provider_id);
CREATE TABLE IF NOT EXISTS public.api_key_provider_mappings (
id character varying(64) NOT NULL,
api_key_id character varying(64) NOT NULL,
provider_id character varying(64) NOT NULL,
priority_adjustment integer DEFAULT 0 NOT NULL,
weight_multiplier double precision DEFAULT 1 NOT NULL,
is_enabled boolean DEFAULT true NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.api_key_provider_mappings ADD CONSTRAINT api_key_provider_mappings_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.api_key_provider_mappings ADD CONSTRAINT uq_apikey_provider UNIQUE (api_key_id, provider_id);
CREATE INDEX IF NOT EXISTS api_key_provider_mappings_api_key_id_idx ON public.api_key_provider_mappings USING btree (api_key_id);
CREATE INDEX IF NOT EXISTS api_key_provider_mappings_provider_id_idx ON public.api_key_provider_mappings USING btree (provider_id);
CREATE INDEX IF NOT EXISTS idx_apikey_provider_enabled ON public.api_key_provider_mappings USING btree (api_key_id, is_enabled);
CREATE TABLE IF NOT EXISTS public.gemini_file_mappings (
id character varying(64) NOT NULL,
file_name character varying(512) NOT NULL,
key_id character varying(64) NOT NULL,
user_id character varying(64),
display_name character varying(512),
mime_type character varying(255),
source_hash character varying(128),
created_at bigint NOT NULL,
expires_at bigint NOT NULL
);
ALTER TABLE ONLY public.gemini_file_mappings ADD CONSTRAINT gemini_file_mappings_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.gemini_file_mappings ADD CONSTRAINT gemini_file_mappings_file_name_key UNIQUE (file_name);
CREATE INDEX IF NOT EXISTS gemini_file_mappings_key_id_idx ON public.gemini_file_mappings USING btree (key_id);
CREATE INDEX IF NOT EXISTS gemini_file_mappings_user_id_idx ON public.gemini_file_mappings USING btree (user_id);
CREATE INDEX IF NOT EXISTS gemini_file_mappings_expires_at_idx ON public.gemini_file_mappings USING btree (expires_at);
CREATE INDEX IF NOT EXISTS gemini_file_mappings_source_hash_idx ON public.gemini_file_mappings USING btree (source_hash);
CREATE TABLE IF NOT EXISTS public.request_candidates (
id character varying(64) NOT NULL,
request_id character varying(128) NOT NULL,
user_id character varying(64),
api_key_id character varying(64),
username character varying(255),
api_key_name character varying(255),
candidate_index integer NOT NULL,
retry_index integer DEFAULT 0 NOT NULL,
provider_id character varying(64),
endpoint_id character varying(64),
key_id character varying(64),
status character varying(32) NOT NULL,
skip_reason text,
is_cached boolean DEFAULT false NOT NULL,
status_code integer,
error_type character varying(128),
error_message text,
latency_ms integer,
concurrent_requests integer,
extra_data jsonb,
required_capabilities jsonb,
created_at bigint NOT NULL,
started_at bigint,
finished_at bigint
);
ALTER TABLE ONLY public.request_candidates ADD CONSTRAINT request_candidates_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.request_candidates ADD CONSTRAINT uq_request_candidate_with_retry UNIQUE (request_id, candidate_index, retry_index);
CREATE INDEX IF NOT EXISTS request_candidates_request_id_idx ON public.request_candidates USING btree (request_id);
CREATE INDEX IF NOT EXISTS request_candidates_provider_id_idx ON public.request_candidates USING btree (provider_id);
CREATE INDEX IF NOT EXISTS request_candidates_endpoint_id_idx ON public.request_candidates USING btree (endpoint_id);
CREATE INDEX IF NOT EXISTS request_candidates_status_idx ON public.request_candidates USING btree (status);
CREATE INDEX IF NOT EXISTS request_candidates_created_at_idx ON public.request_candidates USING btree (created_at);
CREATE INDEX IF NOT EXISTS request_candidates_endpoint_status_created_idx ON public.request_candidates USING btree (endpoint_id, status, created_at);
CREATE TABLE IF NOT EXISTS public.video_tasks (
id character varying(64) NOT NULL,
short_id character varying(32),
request_id character varying(128) NOT NULL,
user_id character varying(64),
api_key_id character varying(64),
username character varying(255),
api_key_name character varying(255),
external_task_id character varying(255),
provider_id character varying(64),
endpoint_id character varying(64),
key_id character varying(64),
client_api_format character varying(128),
provider_api_format character varying(128),
format_converted boolean DEFAULT false NOT NULL,
model character varying(255),
prompt text,
original_request_body jsonb,
converted_request_body jsonb,
duration_seconds integer,
resolution character varying(64),
aspect_ratio character varying(32),
size character varying(64),
status character varying(32) DEFAULT 'pending' NOT NULL,
progress_percent integer DEFAULT 0 NOT NULL,
progress_message text,
retry_count integer DEFAULT 0 NOT NULL,
max_retries integer DEFAULT 3 NOT NULL,
poll_interval_seconds integer DEFAULT 10 NOT NULL,
next_poll_at bigint,
poll_count integer DEFAULT 0 NOT NULL,
max_poll_count integer DEFAULT 360 NOT NULL,
created_at bigint NOT NULL,
submitted_at bigint,
completed_at bigint,
updated_at bigint NOT NULL,
error_code character varying(128),
error_message text,
video_url text,
video_urls jsonb,
thumbnail_url text,
video_size_bytes bigint,
video_expires_at bigint,
stored_video_path character varying(500),
storage_provider character varying(50),
remixed_from_task_id character varying(64),
webhook_url character varying(500),
webhook_sent boolean DEFAULT false NOT NULL,
webhook_sent_at bigint,
request_metadata jsonb,
video_duration_seconds double precision
);
ALTER TABLE ONLY public.video_tasks ADD CONSTRAINT video_tasks_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.video_tasks ADD CONSTRAINT video_tasks_short_id_key UNIQUE (short_id);
ALTER TABLE ONLY public.video_tasks ADD CONSTRAINT video_tasks_request_id_key UNIQUE (request_id);
CREATE INDEX IF NOT EXISTS video_tasks_external_id_idx ON public.video_tasks USING btree (external_task_id);
CREATE INDEX IF NOT EXISTS video_tasks_next_poll_idx ON public.video_tasks USING btree (next_poll_at);
CREATE INDEX IF NOT EXISTS video_tasks_user_status_idx ON public.video_tasks USING btree (user_id, status);
CREATE INDEX IF NOT EXISTS video_tasks_api_key_id_idx ON public.video_tasks USING btree (api_key_id);
CREATE INDEX IF NOT EXISTS video_tasks_provider_id_idx ON public.video_tasks USING btree (provider_id);
CREATE INDEX IF NOT EXISTS video_tasks_endpoint_id_idx ON public.video_tasks USING btree (endpoint_id);
CREATE INDEX IF NOT EXISTS video_tasks_key_id_idx ON public.video_tasks USING btree (key_id);
CREATE TABLE IF NOT EXISTS public.provider_endpoints (
id character varying(64) NOT NULL,
provider_id character varying(64) NOT NULL,
name character varying(255) NOT NULL,
base_url text NOT NULL,
api_format character varying(128),
api_family character varying(128),
endpoint_kind character varying(128),
enabled boolean DEFAULT true NOT NULL,
is_active boolean DEFAULT true NOT NULL,
health_score double precision DEFAULT 1.0 NOT NULL,
weight bigint DEFAULT 1 NOT NULL,
header_rules jsonb,
body_rules jsonb,
max_retries integer,
custom_path text,
metadata jsonb,
config jsonb,
format_acceptance_config jsonb,
proxy jsonb,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.provider_endpoints ADD CONSTRAINT provider_endpoints_pkey PRIMARY KEY (id);
CREATE INDEX IF NOT EXISTS provider_endpoints_provider_id_idx ON public.provider_endpoints USING btree (provider_id);
CREATE TABLE IF NOT EXISTS public.provider_usage_tracking (
id character varying(64) NOT NULL,
provider_id character varying(64) NOT NULL,
window_start bigint NOT NULL,
window_end bigint NOT NULL,
total_requests integer DEFAULT 0 NOT NULL,
successful_requests integer DEFAULT 0 NOT NULL,
failed_requests integer DEFAULT 0 NOT NULL,
avg_response_time_ms double precision DEFAULT 0 NOT NULL,
total_response_time_ms double precision DEFAULT 0 NOT NULL,
total_cost_usd double precision DEFAULT 0 NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.provider_usage_tracking ADD CONSTRAINT provider_usage_tracking_pkey PRIMARY KEY (id);
CREATE INDEX IF NOT EXISTS provider_usage_tracking_provider_id_idx ON public.provider_usage_tracking USING btree (provider_id);
CREATE INDEX IF NOT EXISTS provider_usage_tracking_window_start_idx ON public.provider_usage_tracking USING btree (window_start);
CREATE INDEX IF NOT EXISTS idx_provider_window ON public.provider_usage_tracking USING btree (provider_id, window_start);
CREATE INDEX IF NOT EXISTS idx_window_time ON public.provider_usage_tracking USING btree (window_start, window_end);
CREATE TABLE IF NOT EXISTS public.models (
id character varying(64) NOT NULL,
provider_id character varying(64) NOT NULL,
global_model_id character varying(64),
provider_model_name character varying(255) NOT NULL,
global_model_name character varying(255),
api_format character varying(128),
enabled boolean DEFAULT true NOT NULL,
is_active boolean DEFAULT true NOT NULL,
is_available boolean DEFAULT true NOT NULL,
price_per_request double precision,
tiered_pricing jsonb,
supports_vision boolean,
supports_function_calling boolean,
supports_streaming boolean,
supports_extended_thinking boolean,
supports_image_generation boolean,
provider_model_mappings jsonb,
config jsonb,
metadata jsonb,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.models ADD CONSTRAINT models_pkey PRIMARY KEY (id);
CREATE INDEX IF NOT EXISTS models_provider_id_idx ON public.models USING btree (provider_id);
CREATE TABLE IF NOT EXISTS public.global_models (
id character varying(64) NOT NULL,
name character varying(255) NOT NULL,
display_name character varying(255),
enabled boolean DEFAULT true NOT NULL,
is_active boolean DEFAULT true NOT NULL,
default_price_per_request double precision,
default_tiered_pricing jsonb,
supported_capabilities jsonb,
usage_count bigint DEFAULT 0 NOT NULL,
config jsonb,
metadata jsonb,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.global_models ADD CONSTRAINT global_models_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.global_models ADD CONSTRAINT global_models_name_key UNIQUE (name);

View File

@@ -0,0 +1,85 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS public.system_configs (
id character varying(64) NOT NULL,
key character varying(255) NOT NULL,
value text NOT NULL,
description text,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.system_configs ADD CONSTRAINT system_configs_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.system_configs ADD CONSTRAINT system_configs_key_key UNIQUE (key);
CREATE TABLE IF NOT EXISTS public.auth_modules (
id character varying(64) NOT NULL,
module_type character varying(128) NOT NULL,
enabled boolean DEFAULT true NOT NULL,
config jsonb NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.auth_modules ADD CONSTRAINT auth_modules_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.auth_modules ADD CONSTRAINT auth_modules_module_type_key UNIQUE (module_type);
CREATE TABLE IF NOT EXISTS public.oauth_providers (
provider_type character varying(64) NOT NULL,
display_name character varying(255) NOT NULL,
client_id text NOT NULL,
client_secret_encrypted text,
authorization_url_override character varying(500),
token_url_override character varying(500),
userinfo_url_override character varying(500),
scopes jsonb,
redirect_uri character varying(500) NOT NULL,
frontend_callback_url character varying(500) NOT NULL,
attribute_mapping jsonb,
extra_config jsonb,
is_enabled boolean DEFAULT false NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.oauth_providers ADD CONSTRAINT oauth_providers_pkey PRIMARY KEY (provider_type);
CREATE TABLE IF NOT EXISTS public.ldap_configs (
id bigserial NOT NULL,
server_url character varying(255) NOT NULL,
bind_dn text NOT NULL,
bind_password_encrypted text,
base_dn text NOT NULL,
user_search_filter text DEFAULT '(uid={username})' NOT NULL,
username_attr character varying(50) DEFAULT 'uid' NOT NULL,
email_attr character varying(50) DEFAULT 'mail' NOT NULL,
display_name_attr character varying(50) DEFAULT 'cn' NOT NULL,
is_enabled boolean DEFAULT false NOT NULL,
is_exclusive boolean DEFAULT false NOT NULL,
use_starttls boolean DEFAULT false NOT NULL,
connect_timeout integer DEFAULT 10 NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.ldap_configs ADD CONSTRAINT ldap_configs_pkey PRIMARY KEY (id);
CREATE TABLE IF NOT EXISTS public.user_oauth_links (
id character varying(64) NOT NULL,
user_id character varying(64) NOT NULL,
provider_type character varying(64) NOT NULL,
provider_user_id character varying(255) NOT NULL,
provider_username character varying(255),
provider_email character varying(255),
extra_data jsonb,
linked_at bigint NOT NULL,
last_login_at bigint
);
ALTER TABLE ONLY public.user_oauth_links ADD CONSTRAINT user_oauth_links_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.user_oauth_links ADD CONSTRAINT uq_user_oauth_links_provider_user UNIQUE (provider_type, provider_user_id);
ALTER TABLE ONLY public.user_oauth_links ADD CONSTRAINT uq_user_oauth_links_user_provider UNIQUE (user_id, provider_type);
CREATE INDEX IF NOT EXISTS user_oauth_links_provider_type_idx ON public.user_oauth_links USING btree (provider_type);
CREATE INDEX IF NOT EXISTS user_oauth_links_user_id_idx ON public.user_oauth_links USING btree (user_id);

View File

@@ -0,0 +1,47 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS public.proxy_nodes (
id character varying(64) NOT NULL,
name character varying(255) NOT NULL,
ip character varying(512) NOT NULL,
port integer NOT NULL,
region character varying(100),
status character varying(32) DEFAULT 'online' NOT NULL,
registered_by character varying(64),
last_heartbeat_at bigint,
heartbeat_interval integer DEFAULT 30 NOT NULL,
active_connections integer DEFAULT 0 NOT NULL,
total_requests bigint DEFAULT 0 NOT NULL,
avg_latency_ms double precision,
is_manual boolean DEFAULT false NOT NULL,
proxy_url character varying(500),
proxy_username character varying(255),
proxy_password character varying(500),
created_at bigint NOT NULL,
updated_at bigint NOT NULL,
remote_config jsonb,
config_version integer DEFAULT 0 NOT NULL,
hardware_info jsonb,
estimated_max_concurrency integer,
tunnel_mode boolean DEFAULT false NOT NULL,
tunnel_connected boolean DEFAULT false NOT NULL,
tunnel_connected_at bigint,
failed_requests bigint DEFAULT 0 NOT NULL,
dns_failures bigint DEFAULT 0 NOT NULL,
stream_errors bigint DEFAULT 0 NOT NULL,
proxy_metadata jsonb
);
ALTER TABLE ONLY public.proxy_nodes ADD CONSTRAINT proxy_nodes_pkey PRIMARY KEY (id);
CREATE TABLE IF NOT EXISTS public.proxy_node_events (
id bigserial NOT NULL,
node_id character varying(64) NOT NULL,
event_type character varying(64) NOT NULL,
detail character varying(500),
created_at bigint NOT NULL
);
ALTER TABLE ONLY public.proxy_node_events ADD CONSTRAINT proxy_node_events_pkey PRIMARY KEY (id);

View File

@@ -0,0 +1,203 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS public.wallets (
id character varying(64) NOT NULL,
user_id character varying(64),
api_key_id character varying(64),
balance double precision DEFAULT 0 NOT NULL,
gift_balance double precision DEFAULT 0 NOT NULL,
limit_mode character varying(64) DEFAULT 'finite' NOT NULL,
currency character varying(16) DEFAULT 'USD' NOT NULL,
status character varying(64) DEFAULT 'active' NOT NULL,
total_recharged double precision DEFAULT 0 NOT NULL,
total_consumed double precision DEFAULT 0 NOT NULL,
total_refunded double precision DEFAULT 0 NOT NULL,
total_adjusted double precision DEFAULT 0 NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.wallets ADD CONSTRAINT wallets_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.wallets ADD CONSTRAINT wallets_user_id_key UNIQUE (user_id);
ALTER TABLE ONLY public.wallets ADD CONSTRAINT wallets_api_key_id_key UNIQUE (api_key_id);
CREATE INDEX IF NOT EXISTS wallets_api_key_id_idx ON public.wallets USING btree (api_key_id);
CREATE INDEX IF NOT EXISTS wallets_user_id_idx ON public.wallets USING btree (user_id);
CREATE TABLE IF NOT EXISTS public.wallet_transactions (
id character varying(64) NOT NULL,
wallet_id character varying(64) NOT NULL,
category character varying(64) NOT NULL,
reason_code character varying(64) NOT NULL,
amount double precision NOT NULL,
balance_before double precision NOT NULL,
balance_after double precision NOT NULL,
recharge_balance_before double precision NOT NULL,
recharge_balance_after double precision NOT NULL,
gift_balance_before double precision NOT NULL,
gift_balance_after double precision NOT NULL,
link_type character varying(64),
link_id character varying(128),
operator_id character varying(64),
description text,
created_at bigint NOT NULL
);
ALTER TABLE ONLY public.wallet_transactions ADD CONSTRAINT wallet_transactions_pkey PRIMARY KEY (id);
CREATE INDEX IF NOT EXISTS idx_wallet_tx_wallet_created ON public.wallet_transactions USING btree (wallet_id, created_at);
CREATE INDEX IF NOT EXISTS idx_wallet_tx_category_created ON public.wallet_transactions USING btree (category, created_at);
CREATE INDEX IF NOT EXISTS idx_wallet_tx_reason_created ON public.wallet_transactions USING btree (reason_code, created_at);
CREATE INDEX IF NOT EXISTS idx_wallet_tx_link ON public.wallet_transactions USING btree (link_type, link_id);
CREATE INDEX IF NOT EXISTS ix_wallet_transactions_operator_id ON public.wallet_transactions USING btree (operator_id);
CREATE TABLE IF NOT EXISTS public.wallet_daily_usage_ledgers (
id character varying(64) NOT NULL,
wallet_id character varying(64) NOT NULL,
billing_date character varying(16) NOT NULL,
billing_timezone character varying(64) NOT NULL,
total_cost_usd double precision DEFAULT 0 NOT NULL,
total_requests bigint DEFAULT 0 NOT NULL,
input_tokens bigint DEFAULT 0 NOT NULL,
output_tokens bigint DEFAULT 0 NOT NULL,
cache_creation_tokens bigint DEFAULT 0 NOT NULL,
cache_read_tokens bigint DEFAULT 0 NOT NULL,
first_finalized_at bigint,
last_finalized_at bigint,
aggregated_at bigint NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.wallet_daily_usage_ledgers ADD CONSTRAINT wallet_daily_usage_ledgers_pkey PRIMARY KEY (id);
CREATE INDEX IF NOT EXISTS idx_wallet_daily_usage_wallet_date ON public.wallet_daily_usage_ledgers USING btree (wallet_id, billing_timezone, billing_date);
CREATE TABLE IF NOT EXISTS public.payment_orders (
id character varying(64) NOT NULL,
order_no character varying(128) NOT NULL,
wallet_id character varying(64) NOT NULL,
user_id character varying(64),
amount_usd double precision NOT NULL,
pay_amount double precision,
pay_currency character varying(16),
exchange_rate double precision,
refunded_amount_usd double precision DEFAULT 0 NOT NULL,
refundable_amount_usd double precision DEFAULT 0 NOT NULL,
payment_method character varying(64) NOT NULL,
gateway_order_id character varying(128),
gateway_response jsonb,
status character varying(64) DEFAULT 'pending' NOT NULL,
created_at bigint NOT NULL,
paid_at bigint,
credited_at bigint,
expires_at bigint
);
ALTER TABLE ONLY public.payment_orders ADD CONSTRAINT payment_orders_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.payment_orders ADD CONSTRAINT uq_payment_orders_order_no UNIQUE (order_no);
CREATE INDEX IF NOT EXISTS idx_payment_orders_wallet_created ON public.payment_orders USING btree (wallet_id, created_at);
CREATE INDEX IF NOT EXISTS idx_payment_orders_user_created ON public.payment_orders USING btree (user_id, created_at);
CREATE INDEX IF NOT EXISTS idx_payment_orders_status ON public.payment_orders USING btree (status);
CREATE INDEX IF NOT EXISTS idx_payment_orders_gateway_order_id ON public.payment_orders USING btree (gateway_order_id);
CREATE TABLE IF NOT EXISTS public.payment_callbacks (
id character varying(64) NOT NULL,
payment_order_id character varying(64),
payment_method character varying(64) NOT NULL,
callback_key character varying(128) NOT NULL,
order_no character varying(128),
gateway_order_id character varying(128),
payload_hash character varying(128),
signature_valid boolean DEFAULT false NOT NULL,
status character varying(64) DEFAULT 'received' NOT NULL,
payload jsonb,
error_message text,
created_at bigint NOT NULL,
processed_at bigint
);
ALTER TABLE ONLY public.payment_callbacks ADD CONSTRAINT payment_callbacks_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.payment_callbacks ADD CONSTRAINT uq_payment_callbacks_callback_key UNIQUE (callback_key);
CREATE INDEX IF NOT EXISTS idx_payment_callbacks_order ON public.payment_callbacks USING btree (order_no);
CREATE INDEX IF NOT EXISTS idx_payment_callbacks_gateway_order ON public.payment_callbacks USING btree (gateway_order_id);
CREATE INDEX IF NOT EXISTS idx_payment_callbacks_created ON public.payment_callbacks USING btree (created_at);
CREATE INDEX IF NOT EXISTS ix_payment_callbacks_payment_order_id ON public.payment_callbacks USING btree (payment_order_id);
CREATE TABLE IF NOT EXISTS public.refund_requests (
id character varying(64) NOT NULL,
refund_no character varying(128) NOT NULL,
wallet_id character varying(64) NOT NULL,
user_id character varying(64),
payment_order_id character varying(64),
source_type character varying(64) NOT NULL,
source_id character varying(128),
refund_mode character varying(64) NOT NULL,
amount_usd double precision NOT NULL,
status character varying(64) DEFAULT 'pending_approval' NOT NULL,
reason text,
requested_by character varying(64),
approved_by character varying(64),
processed_by character varying(64),
gateway_refund_id character varying(128),
payout_method character varying(64),
payout_reference character varying(255),
payout_proof jsonb,
failure_reason text,
idempotency_key character varying(128),
created_at bigint NOT NULL,
updated_at bigint NOT NULL,
processed_at bigint,
completed_at bigint
);
ALTER TABLE ONLY public.refund_requests ADD CONSTRAINT refund_requests_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.refund_requests ADD CONSTRAINT uq_refund_requests_refund_no UNIQUE (refund_no);
ALTER TABLE ONLY public.refund_requests ADD CONSTRAINT uq_refund_requests_idempotency_key UNIQUE (idempotency_key);
CREATE INDEX IF NOT EXISTS idx_refund_wallet_created ON public.refund_requests USING btree (wallet_id, created_at);
CREATE INDEX IF NOT EXISTS idx_refund_user_created ON public.refund_requests USING btree (user_id, created_at);
CREATE INDEX IF NOT EXISTS idx_refund_status ON public.refund_requests USING btree (status);
CREATE INDEX IF NOT EXISTS ix_refund_requests_payment_order_id ON public.refund_requests USING btree (payment_order_id);
CREATE INDEX IF NOT EXISTS ix_refund_requests_requested_by ON public.refund_requests USING btree (requested_by);
CREATE INDEX IF NOT EXISTS ix_refund_requests_approved_by ON public.refund_requests USING btree (approved_by);
CREATE INDEX IF NOT EXISTS ix_refund_requests_processed_by ON public.refund_requests USING btree (processed_by);
CREATE TABLE IF NOT EXISTS public.redeem_code_batches (
id character varying(64) NOT NULL,
name character varying(255) NOT NULL,
amount_usd double precision NOT NULL,
currency character varying(16) DEFAULT 'USD' NOT NULL,
balance_bucket character varying(64) DEFAULT 'gift' NOT NULL,
total_count integer NOT NULL,
status character varying(64) DEFAULT 'active' NOT NULL,
description text,
created_by character varying(64),
expires_at bigint,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.redeem_code_batches ADD CONSTRAINT redeem_code_batches_pkey PRIMARY KEY (id);
CREATE INDEX IF NOT EXISTS idx_redeem_code_batches_status ON public.redeem_code_batches USING btree (status, created_at);
CREATE TABLE IF NOT EXISTS public.redeem_codes (
id character varying(64) NOT NULL,
batch_id character varying(64) NOT NULL,
code_hash character varying(128) NOT NULL,
code_prefix character varying(16) NOT NULL,
code_suffix character varying(16) NOT NULL,
status character varying(64) DEFAULT 'active' NOT NULL,
redeemed_by_user_id character varying(64),
redeemed_wallet_id character varying(64),
redeemed_payment_order_id character varying(64),
redeemed_at bigint,
disabled_by character varying(64),
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.redeem_codes ADD CONSTRAINT redeem_codes_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.redeem_codes ADD CONSTRAINT uq_redeem_codes_code_hash UNIQUE (code_hash);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_batch_created ON public.redeem_codes USING btree (batch_id, created_at);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_status ON public.redeem_codes USING btree (status, updated_at);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_redeemed_user ON public.redeem_codes USING btree (redeemed_by_user_id, redeemed_at);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_redeemed_order ON public.redeem_codes USING btree (redeemed_payment_order_id);

View File

@@ -0,0 +1,133 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS public.usage (
request_id character varying(128) NOT NULL,
id character varying(128),
user_id character varying(64),
api_key_id character varying(64),
provider_name character varying(255) DEFAULT 'unknown' NOT NULL,
model character varying(255) DEFAULT 'unknown' NOT NULL,
target_model character varying(255),
provider_id character varying(64),
provider_endpoint_id character varying(64),
provider_api_key_id character varying(64),
request_type character varying(64),
api_format character varying(64),
api_family character varying(64),
endpoint_kind character varying(64),
endpoint_api_format character varying(64),
provider_api_family character varying(64),
provider_endpoint_kind character varying(64),
has_format_conversion boolean DEFAULT false NOT NULL,
is_stream boolean DEFAULT false NOT NULL,
input_tokens bigint DEFAULT 0 NOT NULL,
output_tokens bigint DEFAULT 0 NOT NULL,
input_output_total_tokens bigint DEFAULT 0 NOT NULL,
total_tokens bigint DEFAULT 0 NOT NULL,
cache_creation_input_tokens bigint DEFAULT 0 NOT NULL,
cache_creation_input_tokens_5m bigint DEFAULT 0 NOT NULL,
cache_creation_input_tokens_1h bigint DEFAULT 0 NOT NULL,
cache_creation_ephemeral_5m_input_tokens bigint DEFAULT 0 NOT NULL,
cache_creation_ephemeral_1h_input_tokens bigint DEFAULT 0 NOT NULL,
cache_read_input_tokens bigint DEFAULT 0 NOT NULL,
input_context_tokens bigint DEFAULT 0 NOT NULL,
input_cost_usd double precision DEFAULT 0 NOT NULL,
output_cost_usd double precision DEFAULT 0 NOT NULL,
cache_cost_usd double precision DEFAULT 0 NOT NULL,
cache_creation_cost_usd double precision DEFAULT 0 NOT NULL,
cache_creation_cost_usd_5m double precision DEFAULT 0 NOT NULL,
cache_creation_cost_usd_1h double precision DEFAULT 0 NOT NULL,
cache_read_cost_usd double precision DEFAULT 0 NOT NULL,
request_cost_usd double precision DEFAULT 0 NOT NULL,
actual_input_cost_usd double precision DEFAULT 0 NOT NULL,
actual_output_cost_usd double precision DEFAULT 0 NOT NULL,
actual_cache_cost_usd double precision DEFAULT 0 NOT NULL,
actual_cache_creation_cost_usd double precision DEFAULT 0 NOT NULL,
actual_cache_creation_cost_usd_5m double precision DEFAULT 0 NOT NULL,
actual_cache_creation_cost_usd_1h double precision DEFAULT 0 NOT NULL,
actual_cache_read_cost_usd double precision DEFAULT 0 NOT NULL,
actual_request_cost_usd double precision DEFAULT 0 NOT NULL,
rate_multiplier double precision DEFAULT 1 NOT NULL,
input_price_per_1m double precision,
output_price_per_1m double precision,
cache_creation_price_per_1m double precision,
cache_creation_price_per_1m_5m double precision,
cache_creation_price_per_1m_1h double precision,
cache_read_price_per_1m double precision,
price_per_request double precision,
status_code integer,
error_message text,
error_category character varying(255),
response_time_ms bigint,
first_byte_time_ms bigint,
wallet_id character varying(64),
status character varying(64) DEFAULT 'completed' NOT NULL,
billing_status character varying(64) DEFAULT 'pending' NOT NULL,
total_cost_usd double precision DEFAULT 0 NOT NULL,
actual_total_cost_usd double precision DEFAULT 0 NOT NULL,
request_headers jsonb,
request_body jsonb,
provider_request_headers jsonb,
provider_request_body jsonb,
response_headers jsonb,
response_body jsonb,
client_response_headers jsonb,
client_response_body jsonb,
request_body_compressed bytea,
provider_request_body_compressed bytea,
response_body_compressed bytea,
client_response_body_compressed bytea,
request_metadata jsonb,
created_at bigint,
candidate_id character varying(128),
candidate_index bigint,
key_name character varying(255),
username character varying(255),
api_key_name character varying(255),
planner_kind character varying(64),
route_family character varying(128),
route_kind character varying(128),
execution_path character varying(128),
local_execution_runtime_miss_reason character varying(255),
wallet_balance_before double precision,
wallet_balance_after double precision,
wallet_recharge_balance_before double precision,
wallet_recharge_balance_after double precision,
wallet_gift_balance_before double precision,
wallet_gift_balance_after double precision,
finalized_at bigint,
created_at_unix_ms bigint DEFAULT 0 NOT NULL,
updated_at_unix_secs bigint DEFAULT 0 NOT NULL
);
ALTER TABLE ONLY public.usage ADD CONSTRAINT usage_pkey PRIMARY KEY (request_id);
CREATE INDEX IF NOT EXISTS usage_api_key_id_idx ON public.usage USING btree (api_key_id);
CREATE INDEX IF NOT EXISTS usage_billing_status_idx ON public.usage USING btree (billing_status);
CREATE INDEX IF NOT EXISTS usage_created_at_idx ON public.usage USING btree (created_at_unix_ms);
CREATE INDEX IF NOT EXISTS usage_provider_api_key_id_idx ON public.usage USING btree (provider_api_key_id);
CREATE INDEX IF NOT EXISTS usage_provider_id_idx ON public.usage USING btree (provider_id);
CREATE INDEX IF NOT EXISTS usage_request_id_idx ON public.usage USING btree (request_id);
CREATE INDEX IF NOT EXISTS usage_user_id_idx ON public.usage USING btree (user_id);
CREATE INDEX IF NOT EXISTS usage_wallet_id_idx ON public.usage USING btree (wallet_id);
CREATE TABLE IF NOT EXISTS public.usage_settlement_snapshots (
request_id character varying(128) NOT NULL,
billing_status character varying(64) NOT NULL,
wallet_id character varying(64),
wallet_balance_before double precision,
wallet_balance_after double precision,
wallet_recharge_balance_before double precision,
wallet_recharge_balance_after double precision,
wallet_gift_balance_before double precision,
wallet_gift_balance_after double precision,
provider_monthly_used_usd double precision,
finalized_at bigint,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.usage_settlement_snapshots ADD CONSTRAINT usage_settlement_snapshots_pkey PRIMARY KEY (request_id);
CREATE INDEX IF NOT EXISTS usage_settlement_snapshots_billing_status_idx ON public.usage_settlement_snapshots USING btree (billing_status);
CREATE INDEX IF NOT EXISTS usage_settlement_snapshots_wallet_id_idx ON public.usage_settlement_snapshots USING btree (wallet_id);

View File

@@ -0,0 +1,249 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS public.stats_hourly (
id character varying(64) NOT NULL,
hour_utc bigint NOT NULL,
total_requests bigint DEFAULT 0 NOT NULL,
success_requests bigint DEFAULT 0 NOT NULL,
error_requests bigint DEFAULT 0 NOT NULL,
input_tokens bigint DEFAULT 0 NOT NULL,
output_tokens bigint DEFAULT 0 NOT NULL,
cache_creation_tokens bigint DEFAULT 0 NOT NULL,
cache_read_tokens bigint DEFAULT 0 NOT NULL,
total_cost double precision DEFAULT 0 NOT NULL,
actual_total_cost double precision DEFAULT 0 NOT NULL,
avg_response_time_ms double precision DEFAULT 0 NOT NULL,
is_complete boolean DEFAULT false NOT NULL,
aggregated_at bigint,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.stats_hourly ADD CONSTRAINT stats_hourly_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.stats_hourly ADD CONSTRAINT uq_stats_hourly_hour UNIQUE (hour_utc);
CREATE TABLE IF NOT EXISTS public.stats_summary (
id character varying(64) NOT NULL,
cutoff_date bigint NOT NULL,
all_time_requests bigint DEFAULT 0 NOT NULL,
all_time_success_requests bigint DEFAULT 0 NOT NULL,
all_time_error_requests bigint DEFAULT 0 NOT NULL,
all_time_input_tokens bigint DEFAULT 0 NOT NULL,
all_time_output_tokens bigint DEFAULT 0 NOT NULL,
all_time_cache_creation_tokens bigint DEFAULT 0 NOT NULL,
all_time_cache_read_tokens bigint DEFAULT 0 NOT NULL,
all_time_cost double precision DEFAULT 0 NOT NULL,
all_time_actual_cost double precision DEFAULT 0 NOT NULL,
total_users bigint DEFAULT 0 NOT NULL,
active_users bigint DEFAULT 0 NOT NULL,
total_api_keys bigint DEFAULT 0 NOT NULL,
active_api_keys bigint DEFAULT 0 NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.stats_summary ADD CONSTRAINT stats_summary_pkey PRIMARY KEY (id);
CREATE TABLE IF NOT EXISTS public.stats_hourly_user (
id character varying(64) NOT NULL,
hour_utc bigint NOT NULL,
user_id character varying(64) NOT NULL,
total_requests bigint DEFAULT 0 NOT NULL,
success_requests bigint DEFAULT 0 NOT NULL,
error_requests bigint DEFAULT 0 NOT NULL,
input_tokens bigint DEFAULT 0 NOT NULL,
output_tokens bigint DEFAULT 0 NOT NULL,
total_cost double precision DEFAULT 0 NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.stats_hourly_user ADD CONSTRAINT stats_hourly_user_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.stats_hourly_user ADD CONSTRAINT uq_stats_hourly_user UNIQUE (hour_utc, user_id);
CREATE TABLE IF NOT EXISTS public.stats_hourly_user_model (
id character varying(64) NOT NULL,
hour_utc bigint NOT NULL,
user_id character varying(64) NOT NULL,
model character varying(255) NOT NULL,
total_requests bigint DEFAULT 0 NOT NULL,
input_tokens bigint DEFAULT 0 NOT NULL,
output_tokens bigint DEFAULT 0 NOT NULL,
total_cost double precision DEFAULT 0 NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.stats_hourly_user_model ADD CONSTRAINT stats_hourly_user_model_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.stats_hourly_user_model ADD CONSTRAINT uq_stats_hourly_user_model UNIQUE (hour_utc, user_id, model);
CREATE TABLE IF NOT EXISTS public.user_model_usage_counts (
id character varying(64) NOT NULL,
user_id character varying(64) NOT NULL,
model character varying(255) NOT NULL,
usage_count bigint DEFAULT 0 NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.user_model_usage_counts ADD CONSTRAINT user_model_usage_counts_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.user_model_usage_counts ADD CONSTRAINT uq_user_model_usage_count UNIQUE (user_id, model);
CREATE INDEX IF NOT EXISTS idx_user_model_usage_user ON public.user_model_usage_counts USING btree (user_id);
CREATE INDEX IF NOT EXISTS idx_user_model_usage_model ON public.user_model_usage_counts USING btree (model);
CREATE TABLE IF NOT EXISTS public.stats_hourly_model (
id character varying(64) NOT NULL,
hour_utc bigint NOT NULL,
model character varying(255) NOT NULL,
total_requests bigint DEFAULT 0 NOT NULL,
input_tokens bigint DEFAULT 0 NOT NULL,
output_tokens bigint DEFAULT 0 NOT NULL,
total_cost double precision DEFAULT 0 NOT NULL,
avg_response_time_ms double precision DEFAULT 0 NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.stats_hourly_model ADD CONSTRAINT stats_hourly_model_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.stats_hourly_model ADD CONSTRAINT uq_stats_hourly_model UNIQUE (hour_utc, model);
CREATE TABLE IF NOT EXISTS public.stats_hourly_provider (
id character varying(64) NOT NULL,
hour_utc bigint NOT NULL,
provider_name character varying(255) NOT NULL,
total_requests bigint DEFAULT 0 NOT NULL,
input_tokens bigint DEFAULT 0 NOT NULL,
output_tokens bigint DEFAULT 0 NOT NULL,
total_cost double precision DEFAULT 0 NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.stats_hourly_provider ADD CONSTRAINT stats_hourly_provider_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.stats_hourly_provider ADD CONSTRAINT uq_stats_hourly_provider UNIQUE (hour_utc, provider_name);
CREATE TABLE IF NOT EXISTS public.stats_daily (
id character varying(64) NOT NULL,
date bigint NOT NULL,
total_requests bigint DEFAULT 0 NOT NULL,
success_requests bigint DEFAULT 0 NOT NULL,
error_requests bigint DEFAULT 0 NOT NULL,
input_tokens bigint DEFAULT 0 NOT NULL,
output_tokens bigint DEFAULT 0 NOT NULL,
cache_creation_tokens bigint DEFAULT 0 NOT NULL,
cache_read_tokens bigint DEFAULT 0 NOT NULL,
total_cost double precision DEFAULT 0 NOT NULL,
actual_total_cost double precision DEFAULT 0 NOT NULL,
input_cost double precision DEFAULT 0 NOT NULL,
output_cost double precision DEFAULT 0 NOT NULL,
cache_creation_cost double precision DEFAULT 0 NOT NULL,
cache_read_cost double precision DEFAULT 0 NOT NULL,
avg_response_time_ms double precision DEFAULT 0 NOT NULL,
fallback_count bigint DEFAULT 0 NOT NULL,
unique_models bigint DEFAULT 0 NOT NULL,
unique_providers bigint DEFAULT 0 NOT NULL,
is_complete boolean DEFAULT false NOT NULL,
aggregated_at bigint,
created_at bigint NOT NULL,
updated_at bigint NOT NULL,
p50_response_time_ms bigint,
p90_response_time_ms bigint,
p99_response_time_ms bigint,
p50_first_byte_time_ms bigint,
p90_first_byte_time_ms bigint,
p99_first_byte_time_ms bigint
);
ALTER TABLE ONLY public.stats_daily ADD CONSTRAINT stats_daily_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.stats_daily ADD CONSTRAINT uq_stats_daily_date UNIQUE (date);
CREATE TABLE IF NOT EXISTS public.stats_daily_model (
id character varying(64) NOT NULL,
date bigint NOT NULL,
model character varying(255) NOT NULL,
total_requests bigint DEFAULT 0 NOT NULL,
input_tokens bigint DEFAULT 0 NOT NULL,
output_tokens bigint DEFAULT 0 NOT NULL,
cache_creation_tokens bigint DEFAULT 0 NOT NULL,
cache_read_tokens bigint DEFAULT 0 NOT NULL,
total_cost double precision DEFAULT 0 NOT NULL,
avg_response_time_ms double precision DEFAULT 0 NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.stats_daily_model ADD CONSTRAINT stats_daily_model_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.stats_daily_model ADD CONSTRAINT uq_stats_daily_model UNIQUE (date, model);
CREATE TABLE IF NOT EXISTS public.stats_daily_provider (
id character varying(64) NOT NULL,
date bigint NOT NULL,
provider_name character varying(255) NOT NULL,
total_requests bigint DEFAULT 0 NOT NULL,
input_tokens bigint DEFAULT 0 NOT NULL,
output_tokens bigint DEFAULT 0 NOT NULL,
cache_creation_tokens bigint DEFAULT 0 NOT NULL,
cache_read_tokens bigint DEFAULT 0 NOT NULL,
total_cost double precision DEFAULT 0 NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.stats_daily_provider ADD CONSTRAINT stats_daily_provider_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.stats_daily_provider ADD CONSTRAINT uq_stats_daily_provider UNIQUE (date, provider_name);
CREATE TABLE IF NOT EXISTS public.stats_daily_api_key (
id character varying(64) NOT NULL,
api_key_id character varying(64) NOT NULL,
date bigint NOT NULL,
total_requests bigint DEFAULT 0 NOT NULL,
success_requests bigint DEFAULT 0 NOT NULL,
error_requests bigint DEFAULT 0 NOT NULL,
input_tokens bigint DEFAULT 0 NOT NULL,
output_tokens bigint DEFAULT 0 NOT NULL,
cache_creation_tokens bigint DEFAULT 0 NOT NULL,
cache_read_tokens bigint DEFAULT 0 NOT NULL,
total_cost double precision DEFAULT 0 NOT NULL,
api_key_name character varying(255),
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.stats_daily_api_key ADD CONSTRAINT stats_daily_api_key_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.stats_daily_api_key ADD CONSTRAINT uq_stats_daily_api_key UNIQUE (date, api_key_id);
CREATE TABLE IF NOT EXISTS public.stats_daily_error (
id character varying(64) NOT NULL,
date bigint NOT NULL,
error_category character varying(255) NOT NULL,
provider_name character varying(255),
model character varying(255),
count bigint DEFAULT 0 NOT NULL,
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.stats_daily_error ADD CONSTRAINT stats_daily_error_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.stats_daily_error ADD CONSTRAINT uq_stats_daily_error UNIQUE (date, error_category, provider_name, model);
CREATE TABLE IF NOT EXISTS public.stats_user_daily (
id character varying(64) NOT NULL,
user_id character varying(64) NOT NULL,
date bigint NOT NULL,
total_requests bigint DEFAULT 0 NOT NULL,
success_requests bigint DEFAULT 0 NOT NULL,
error_requests bigint DEFAULT 0 NOT NULL,
input_tokens bigint DEFAULT 0 NOT NULL,
output_tokens bigint DEFAULT 0 NOT NULL,
cache_creation_tokens bigint DEFAULT 0 NOT NULL,
cache_read_tokens bigint DEFAULT 0 NOT NULL,
total_cost double precision DEFAULT 0 NOT NULL,
username character varying(255),
created_at bigint NOT NULL,
updated_at bigint NOT NULL
);
ALTER TABLE ONLY public.stats_user_daily ADD CONSTRAINT stats_user_daily_pkey PRIMARY KEY (id);
ALTER TABLE ONLY public.stats_user_daily ADD CONSTRAINT uq_stats_user_daily UNIQUE (date, user_id);

View File

@@ -0,0 +1,10 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
001_identity.sql
002_provider_catalog.sql
003_auth_config.sql
004_proxy_nodes.sql
005_wallet_billing.sql
006_usage.sql
007_stats.sql

View File

@@ -0,0 +1,172 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY NOT NULL,
external_id TEXT,
email TEXT,
username TEXT,
password_hash TEXT,
role TEXT,
auth_source TEXT NOT NULL DEFAULT 'local',
email_verified INTEGER NOT NULL DEFAULT 0,
is_active INTEGER NOT NULL DEFAULT 1,
is_deleted INTEGER NOT NULL DEFAULT 0,
allowed_models TEXT,
allowed_providers TEXT,
allowed_api_formats TEXT,
model_capability_settings TEXT,
rate_limit INTEGER,
metadata TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
last_login_at INTEGER,
ldap_dn TEXT,
ldap_username TEXT,
UNIQUE (email),
UNIQUE (username)
);
CREATE TABLE IF NOT EXISTS api_keys (
id TEXT PRIMARY KEY NOT NULL,
user_id TEXT NOT NULL,
key_hash TEXT NOT NULL,
key_encrypted TEXT,
name TEXT,
key_prefix TEXT,
status TEXT NOT NULL DEFAULT 'active',
allowed_models TEXT,
allowed_providers TEXT,
allowed_api_formats TEXT,
rate_limit INTEGER DEFAULT 100,
concurrent_limit INTEGER,
force_capabilities TEXT,
is_active INTEGER NOT NULL DEFAULT 1,
is_locked INTEGER NOT NULL DEFAULT 0,
is_standalone INTEGER NOT NULL DEFAULT 0,
auto_delete_on_expiry INTEGER NOT NULL DEFAULT 0,
total_requests INTEGER NOT NULL DEFAULT 0,
total_tokens INTEGER NOT NULL DEFAULT 0,
total_cost_usd REAL NOT NULL DEFAULT 0,
metadata TEXT,
expires_at INTEGER,
last_used_at INTEGER,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (key_hash)
);
CREATE INDEX IF NOT EXISTS api_keys_user_id_idx ON api_keys (user_id);
CREATE TABLE IF NOT EXISTS audit_logs (
id TEXT PRIMARY KEY NOT NULL,
event_type TEXT NOT NULL,
user_id TEXT,
api_key_id TEXT,
description TEXT NOT NULL,
ip_address TEXT,
user_agent TEXT,
request_id TEXT,
event_metadata TEXT,
status_code INTEGER,
error_message TEXT,
created_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS audit_logs_created_at_idx ON audit_logs (created_at);
CREATE INDEX IF NOT EXISTS audit_logs_event_type_idx ON audit_logs (event_type);
CREATE INDEX IF NOT EXISTS audit_logs_request_id_idx ON audit_logs (request_id);
CREATE INDEX IF NOT EXISTS audit_logs_user_id_idx ON audit_logs (user_id);
CREATE TABLE IF NOT EXISTS announcements (
id TEXT PRIMARY KEY NOT NULL,
title TEXT NOT NULL,
content TEXT NOT NULL,
type TEXT NOT NULL DEFAULT 'info',
priority INTEGER NOT NULL DEFAULT 0,
author_id TEXT,
is_active INTEGER NOT NULL DEFAULT 1,
is_pinned INTEGER NOT NULL DEFAULT 0,
start_time INTEGER,
end_time INTEGER,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS announcements_author_id_idx ON announcements (author_id);
CREATE INDEX IF NOT EXISTS announcements_created_at_idx ON announcements (created_at);
CREATE INDEX IF NOT EXISTS announcements_is_active_idx ON announcements (is_active);
CREATE TABLE IF NOT EXISTS announcement_reads (
id TEXT PRIMARY KEY NOT NULL,
user_id TEXT NOT NULL,
announcement_id TEXT NOT NULL,
read_at INTEGER NOT NULL,
UNIQUE (user_id, announcement_id)
);
CREATE INDEX IF NOT EXISTS announcement_reads_announcement_id_idx ON announcement_reads (announcement_id);
CREATE INDEX IF NOT EXISTS announcement_reads_user_id_idx ON announcement_reads (user_id);
CREATE TABLE IF NOT EXISTS management_tokens (
id TEXT PRIMARY KEY NOT NULL,
user_id TEXT NOT NULL,
name TEXT NOT NULL,
description TEXT,
token_hash TEXT NOT NULL,
token_prefix TEXT,
allowed_ips TEXT,
expires_at INTEGER,
last_used_at INTEGER,
last_used_ip TEXT,
usage_count INTEGER NOT NULL DEFAULT 0,
is_active INTEGER NOT NULL DEFAULT 1,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (token_hash),
UNIQUE (user_id, name)
);
CREATE INDEX IF NOT EXISTS management_tokens_user_id_idx ON management_tokens (user_id);
CREATE TABLE IF NOT EXISTS user_preferences (
id TEXT PRIMARY KEY NOT NULL,
user_id TEXT NOT NULL,
avatar_url TEXT,
bio TEXT,
default_provider_id TEXT,
theme TEXT NOT NULL DEFAULT 'light',
language TEXT NOT NULL DEFAULT 'zh-CN',
timezone TEXT NOT NULL DEFAULT 'Asia/Shanghai',
email_notifications INTEGER NOT NULL DEFAULT 1,
usage_alerts INTEGER NOT NULL DEFAULT 1,
announcement_notifications INTEGER NOT NULL DEFAULT 1,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (user_id)
);
CREATE INDEX IF NOT EXISTS user_preferences_default_provider_id_idx ON user_preferences (default_provider_id);
CREATE INDEX IF NOT EXISTS user_preferences_user_id_idx ON user_preferences (user_id);
CREATE TABLE IF NOT EXISTS user_sessions (
id TEXT PRIMARY KEY NOT NULL,
user_id TEXT NOT NULL,
client_device_id TEXT NOT NULL,
device_label TEXT,
device_type TEXT NOT NULL DEFAULT 'unknown',
browser_name TEXT,
browser_version TEXT,
os_name TEXT,
os_version TEXT,
device_model TEXT,
ip_address TEXT,
user_agent TEXT,
client_hints TEXT,
refresh_token_hash TEXT NOT NULL,
prev_refresh_token_hash TEXT,
rotated_at INTEGER,
last_seen_at INTEGER NOT NULL,
expires_at INTEGER NOT NULL,
revoked_at INTEGER,
revoke_reason TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS user_sessions_user_active_idx ON user_sessions (user_id, revoked_at, expires_at);
CREATE INDEX IF NOT EXISTS user_sessions_user_device_idx ON user_sessions (user_id, client_device_id);

View File

@@ -0,0 +1,342 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS billing_rules (
id TEXT PRIMARY KEY NOT NULL,
global_model_id TEXT,
model_id TEXT,
name TEXT NOT NULL,
task_type TEXT NOT NULL DEFAULT 'chat',
expression TEXT NOT NULL,
variables TEXT NOT NULL,
dimension_mappings TEXT NOT NULL,
is_enabled INTEGER NOT NULL DEFAULT 1,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS billing_rules_global_model_task_idx ON billing_rules (global_model_id, task_type, is_enabled);
CREATE INDEX IF NOT EXISTS billing_rules_model_task_idx ON billing_rules (model_id, task_type, is_enabled);
CREATE TABLE IF NOT EXISTS dimension_collectors (
id TEXT PRIMARY KEY NOT NULL,
api_format TEXT NOT NULL,
task_type TEXT NOT NULL,
dimension_name TEXT NOT NULL,
source_type TEXT NOT NULL,
source_path TEXT,
value_type TEXT NOT NULL DEFAULT 'float',
transform_expression TEXT,
default_value TEXT,
priority INTEGER NOT NULL DEFAULT 0,
is_enabled INTEGER NOT NULL DEFAULT 1,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS dimension_collectors_enabled_idx ON dimension_collectors (api_format, task_type, dimension_name, priority, is_enabled);
CREATE TABLE IF NOT EXISTS providers (
id TEXT PRIMARY KEY NOT NULL,
name TEXT NOT NULL,
description TEXT,
website TEXT,
provider_type TEXT NOT NULL,
billing_type TEXT,
monthly_quota_usd REAL,
monthly_used_usd REAL,
quota_reset_day INTEGER,
quota_last_reset_at INTEGER,
quota_expires_at INTEGER,
enabled INTEGER NOT NULL DEFAULT 1,
is_active INTEGER NOT NULL DEFAULT 1,
priority INTEGER NOT NULL DEFAULT 0,
provider_priority INTEGER NOT NULL DEFAULT 100,
keep_priority_on_conversion INTEGER NOT NULL DEFAULT 0,
enable_format_conversion INTEGER NOT NULL DEFAULT 1,
concurrent_limit INTEGER,
max_retries INTEGER,
proxy TEXT,
request_timeout REAL,
stream_first_byte_timeout REAL,
config TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (name)
);
CREATE TABLE IF NOT EXISTS provider_api_keys (
id TEXT PRIMARY KEY NOT NULL,
provider_id TEXT NOT NULL,
name TEXT NOT NULL,
api_key TEXT,
encrypted_key TEXT,
auth_type TEXT NOT NULL DEFAULT 'api_key',
auth_config TEXT,
note TEXT,
internal_priority INTEGER NOT NULL DEFAULT 50,
capabilities TEXT,
api_formats TEXT,
auth_type_by_format TEXT,
allow_auth_channel_mismatch_formats TEXT,
rate_multipliers TEXT,
global_priority_by_format TEXT,
allowed_models TEXT,
expires_at INTEGER,
cache_ttl_minutes INTEGER NOT NULL DEFAULT 5,
max_probe_interval_minutes INTEGER NOT NULL DEFAULT 32,
proxy TEXT,
fingerprint TEXT,
concurrent_limit INTEGER,
learned_rpm_limit INTEGER,
concurrent_429_count INTEGER NOT NULL DEFAULT 0,
rpm_429_count INTEGER NOT NULL DEFAULT 0,
last_429_at INTEGER,
last_429_type TEXT,
adjustment_history TEXT,
utilization_samples TEXT,
last_probe_increase_at INTEGER,
last_rpm_peak INTEGER,
request_count INTEGER NOT NULL DEFAULT 0,
total_tokens INTEGER NOT NULL DEFAULT 0,
total_cost_usd REAL NOT NULL DEFAULT 0,
success_count INTEGER NOT NULL DEFAULT 0,
error_count INTEGER NOT NULL DEFAULT 0,
total_response_time_ms INTEGER NOT NULL DEFAULT 0,
last_used_at INTEGER,
last_error_at INTEGER,
last_error_msg TEXT,
auto_fetch_models INTEGER NOT NULL DEFAULT 0,
last_models_fetch_at INTEGER,
last_models_fetch_error TEXT,
locked_models TEXT,
model_include_patterns TEXT,
model_exclude_patterns TEXT,
upstream_metadata TEXT,
oauth_invalid_at INTEGER,
oauth_invalid_reason TEXT,
status_snapshot TEXT,
health_by_format TEXT,
circuit_breaker_by_format TEXT,
status TEXT NOT NULL DEFAULT 'active',
is_active INTEGER NOT NULL DEFAULT 1,
weight INTEGER NOT NULL DEFAULT 1,
rpm_limit INTEGER,
metadata TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS provider_api_keys_provider_id_idx ON provider_api_keys (provider_id);
CREATE TABLE IF NOT EXISTS api_key_provider_mappings (
id TEXT PRIMARY KEY NOT NULL,
api_key_id TEXT NOT NULL,
provider_id TEXT NOT NULL,
priority_adjustment INTEGER NOT NULL DEFAULT 0,
weight_multiplier REAL NOT NULL DEFAULT 1,
is_enabled INTEGER NOT NULL DEFAULT 1,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (api_key_id, provider_id)
);
CREATE INDEX IF NOT EXISTS api_key_provider_mappings_api_key_id_idx ON api_key_provider_mappings (api_key_id);
CREATE INDEX IF NOT EXISTS api_key_provider_mappings_provider_id_idx ON api_key_provider_mappings (provider_id);
CREATE INDEX IF NOT EXISTS idx_apikey_provider_enabled ON api_key_provider_mappings (api_key_id, is_enabled);
CREATE TABLE IF NOT EXISTS gemini_file_mappings (
id TEXT PRIMARY KEY NOT NULL,
file_name TEXT NOT NULL,
key_id TEXT NOT NULL,
user_id TEXT,
display_name TEXT,
mime_type TEXT,
source_hash TEXT,
created_at INTEGER NOT NULL,
expires_at INTEGER NOT NULL,
UNIQUE (file_name)
);
CREATE INDEX IF NOT EXISTS gemini_file_mappings_key_id_idx ON gemini_file_mappings (key_id);
CREATE INDEX IF NOT EXISTS gemini_file_mappings_user_id_idx ON gemini_file_mappings (user_id);
CREATE INDEX IF NOT EXISTS gemini_file_mappings_expires_at_idx ON gemini_file_mappings (expires_at);
CREATE INDEX IF NOT EXISTS gemini_file_mappings_source_hash_idx ON gemini_file_mappings (source_hash);
CREATE TABLE IF NOT EXISTS request_candidates (
id TEXT PRIMARY KEY NOT NULL,
request_id TEXT NOT NULL,
user_id TEXT,
api_key_id TEXT,
username TEXT,
api_key_name TEXT,
candidate_index INTEGER NOT NULL,
retry_index INTEGER NOT NULL DEFAULT 0,
provider_id TEXT,
endpoint_id TEXT,
key_id TEXT,
status TEXT NOT NULL,
skip_reason TEXT,
is_cached INTEGER NOT NULL DEFAULT 0,
status_code INTEGER,
error_type TEXT,
error_message TEXT,
latency_ms INTEGER,
concurrent_requests INTEGER,
extra_data TEXT,
required_capabilities TEXT,
created_at INTEGER NOT NULL,
started_at INTEGER,
finished_at INTEGER,
UNIQUE (request_id, candidate_index, retry_index)
);
CREATE INDEX IF NOT EXISTS request_candidates_request_id_idx ON request_candidates (request_id);
CREATE INDEX IF NOT EXISTS request_candidates_provider_id_idx ON request_candidates (provider_id);
CREATE INDEX IF NOT EXISTS request_candidates_endpoint_id_idx ON request_candidates (endpoint_id);
CREATE INDEX IF NOT EXISTS request_candidates_status_idx ON request_candidates (status);
CREATE INDEX IF NOT EXISTS request_candidates_created_at_idx ON request_candidates (created_at);
CREATE INDEX IF NOT EXISTS request_candidates_endpoint_status_created_idx ON request_candidates (endpoint_id, status, created_at);
CREATE TABLE IF NOT EXISTS video_tasks (
id TEXT PRIMARY KEY NOT NULL,
short_id TEXT,
request_id TEXT NOT NULL,
user_id TEXT,
api_key_id TEXT,
username TEXT,
api_key_name TEXT,
external_task_id TEXT,
provider_id TEXT,
endpoint_id TEXT,
key_id TEXT,
client_api_format TEXT,
provider_api_format TEXT,
format_converted INTEGER NOT NULL DEFAULT 0,
model TEXT,
prompt TEXT,
original_request_body TEXT,
converted_request_body TEXT,
duration_seconds INTEGER,
resolution TEXT,
aspect_ratio TEXT,
size TEXT,
status TEXT NOT NULL DEFAULT 'pending',
progress_percent INTEGER NOT NULL DEFAULT 0,
progress_message TEXT,
retry_count INTEGER NOT NULL DEFAULT 0,
max_retries INTEGER NOT NULL DEFAULT 3,
poll_interval_seconds INTEGER NOT NULL DEFAULT 10,
next_poll_at INTEGER,
poll_count INTEGER NOT NULL DEFAULT 0,
max_poll_count INTEGER NOT NULL DEFAULT 360,
created_at INTEGER NOT NULL,
submitted_at INTEGER,
completed_at INTEGER,
updated_at INTEGER NOT NULL,
error_code TEXT,
error_message TEXT,
video_url TEXT,
video_urls TEXT,
thumbnail_url TEXT,
video_size_bytes INTEGER,
video_expires_at INTEGER,
stored_video_path TEXT,
storage_provider TEXT,
remixed_from_task_id TEXT,
webhook_url TEXT,
webhook_sent INTEGER NOT NULL DEFAULT 0,
webhook_sent_at INTEGER,
request_metadata TEXT,
video_duration_seconds REAL,
UNIQUE (short_id),
UNIQUE (request_id)
);
CREATE INDEX IF NOT EXISTS video_tasks_external_id_idx ON video_tasks (external_task_id);
CREATE INDEX IF NOT EXISTS video_tasks_next_poll_idx ON video_tasks (next_poll_at);
CREATE INDEX IF NOT EXISTS video_tasks_user_status_idx ON video_tasks (user_id, status);
CREATE INDEX IF NOT EXISTS video_tasks_api_key_id_idx ON video_tasks (api_key_id);
CREATE INDEX IF NOT EXISTS video_tasks_provider_id_idx ON video_tasks (provider_id);
CREATE INDEX IF NOT EXISTS video_tasks_endpoint_id_idx ON video_tasks (endpoint_id);
CREATE INDEX IF NOT EXISTS video_tasks_key_id_idx ON video_tasks (key_id);
CREATE TABLE IF NOT EXISTS provider_endpoints (
id TEXT PRIMARY KEY NOT NULL,
provider_id TEXT NOT NULL,
name TEXT NOT NULL,
base_url TEXT NOT NULL,
api_format TEXT,
api_family TEXT,
endpoint_kind TEXT,
enabled INTEGER NOT NULL DEFAULT 1,
is_active INTEGER NOT NULL DEFAULT 1,
health_score REAL NOT NULL DEFAULT 1.0,
weight INTEGER NOT NULL DEFAULT 1,
header_rules TEXT,
body_rules TEXT,
max_retries INTEGER,
custom_path TEXT,
metadata TEXT,
config TEXT,
format_acceptance_config TEXT,
proxy TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS provider_endpoints_provider_id_idx ON provider_endpoints (provider_id);
CREATE TABLE IF NOT EXISTS provider_usage_tracking (
id TEXT PRIMARY KEY NOT NULL,
provider_id TEXT NOT NULL,
window_start INTEGER NOT NULL,
window_end INTEGER NOT NULL,
total_requests INTEGER NOT NULL DEFAULT 0,
successful_requests INTEGER NOT NULL DEFAULT 0,
failed_requests INTEGER NOT NULL DEFAULT 0,
avg_response_time_ms REAL NOT NULL DEFAULT 0,
total_response_time_ms REAL NOT NULL DEFAULT 0,
total_cost_usd REAL NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS provider_usage_tracking_provider_id_idx ON provider_usage_tracking (provider_id);
CREATE INDEX IF NOT EXISTS provider_usage_tracking_window_start_idx ON provider_usage_tracking (window_start);
CREATE INDEX IF NOT EXISTS idx_provider_window ON provider_usage_tracking (provider_id, window_start);
CREATE INDEX IF NOT EXISTS idx_window_time ON provider_usage_tracking (window_start, window_end);
CREATE TABLE IF NOT EXISTS models (
id TEXT PRIMARY KEY NOT NULL,
provider_id TEXT NOT NULL,
global_model_id TEXT,
provider_model_name TEXT NOT NULL,
global_model_name TEXT,
api_format TEXT,
enabled INTEGER NOT NULL DEFAULT 1,
is_active INTEGER NOT NULL DEFAULT 1,
is_available INTEGER NOT NULL DEFAULT 1,
price_per_request REAL,
tiered_pricing TEXT,
supports_vision INTEGER,
supports_function_calling INTEGER,
supports_streaming INTEGER,
supports_extended_thinking INTEGER,
supports_image_generation INTEGER,
provider_model_mappings TEXT,
config TEXT,
metadata TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS models_provider_id_idx ON models (provider_id);
CREATE TABLE IF NOT EXISTS global_models (
id TEXT PRIMARY KEY NOT NULL,
name TEXT NOT NULL,
display_name TEXT,
enabled INTEGER NOT NULL DEFAULT 1,
is_active INTEGER NOT NULL DEFAULT 1,
default_price_per_request REAL,
default_tiered_pricing TEXT,
supported_capabilities TEXT,
usage_count INTEGER NOT NULL DEFAULT 0,
config TEXT,
metadata TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (name)
);

View File

@@ -0,0 +1,75 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS system_configs (
id TEXT PRIMARY KEY NOT NULL,
key TEXT NOT NULL,
value TEXT NOT NULL,
description TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (key)
);
CREATE TABLE IF NOT EXISTS auth_modules (
id TEXT PRIMARY KEY NOT NULL,
module_type TEXT NOT NULL,
enabled INTEGER NOT NULL DEFAULT 1,
config TEXT NOT NULL,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (module_type)
);
CREATE TABLE IF NOT EXISTS oauth_providers (
provider_type TEXT PRIMARY KEY NOT NULL,
display_name TEXT NOT NULL,
client_id TEXT NOT NULL,
client_secret_encrypted TEXT,
authorization_url_override TEXT,
token_url_override TEXT,
userinfo_url_override TEXT,
scopes TEXT,
redirect_uri TEXT NOT NULL,
frontend_callback_url TEXT NOT NULL,
attribute_mapping TEXT,
extra_config TEXT,
is_enabled INTEGER NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS ldap_configs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
server_url TEXT NOT NULL,
bind_dn TEXT NOT NULL,
bind_password_encrypted TEXT,
base_dn TEXT NOT NULL,
user_search_filter TEXT NOT NULL DEFAULT '(uid={username})',
username_attr TEXT NOT NULL DEFAULT 'uid',
email_attr TEXT NOT NULL DEFAULT 'mail',
display_name_attr TEXT NOT NULL DEFAULT 'cn',
is_enabled INTEGER NOT NULL DEFAULT 0,
is_exclusive INTEGER NOT NULL DEFAULT 0,
use_starttls INTEGER NOT NULL DEFAULT 0,
connect_timeout INTEGER NOT NULL DEFAULT 10,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS user_oauth_links (
id TEXT PRIMARY KEY NOT NULL,
user_id TEXT NOT NULL,
provider_type TEXT NOT NULL,
provider_user_id TEXT NOT NULL,
provider_username TEXT,
provider_email TEXT,
extra_data TEXT,
linked_at INTEGER NOT NULL,
last_login_at INTEGER,
UNIQUE (provider_type, provider_user_id),
UNIQUE (user_id, provider_type)
);
CREATE INDEX IF NOT EXISTS user_oauth_links_provider_type_idx ON user_oauth_links (provider_type);
CREATE INDEX IF NOT EXISTS user_oauth_links_user_id_idx ON user_oauth_links (user_id);

View File

@@ -0,0 +1,43 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS proxy_nodes (
id TEXT PRIMARY KEY NOT NULL,
name TEXT NOT NULL,
ip TEXT NOT NULL,
port INTEGER NOT NULL,
region TEXT,
status TEXT NOT NULL DEFAULT 'online',
registered_by TEXT,
last_heartbeat_at INTEGER,
heartbeat_interval INTEGER NOT NULL DEFAULT 30,
active_connections INTEGER NOT NULL DEFAULT 0,
total_requests INTEGER NOT NULL DEFAULT 0,
avg_latency_ms REAL,
is_manual INTEGER NOT NULL DEFAULT 0,
proxy_url TEXT,
proxy_username TEXT,
proxy_password TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
remote_config TEXT,
config_version INTEGER NOT NULL DEFAULT 0,
hardware_info TEXT,
estimated_max_concurrency INTEGER,
tunnel_mode INTEGER NOT NULL DEFAULT 0,
tunnel_connected INTEGER NOT NULL DEFAULT 0,
tunnel_connected_at INTEGER,
failed_requests INTEGER NOT NULL DEFAULT 0,
dns_failures INTEGER NOT NULL DEFAULT 0,
stream_errors INTEGER NOT NULL DEFAULT 0,
proxy_metadata TEXT
);
CREATE TABLE IF NOT EXISTS proxy_node_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
node_id TEXT NOT NULL,
event_type TEXT NOT NULL,
detail TEXT,
created_at INTEGER NOT NULL
);

View File

@@ -0,0 +1,187 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS wallets (
id TEXT PRIMARY KEY NOT NULL,
user_id TEXT,
api_key_id TEXT,
balance REAL NOT NULL DEFAULT 0,
gift_balance REAL NOT NULL DEFAULT 0,
limit_mode TEXT NOT NULL DEFAULT 'finite',
currency TEXT NOT NULL DEFAULT 'USD',
status TEXT NOT NULL DEFAULT 'active',
total_recharged REAL NOT NULL DEFAULT 0,
total_consumed REAL NOT NULL DEFAULT 0,
total_refunded REAL NOT NULL DEFAULT 0,
total_adjusted REAL NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (user_id),
UNIQUE (api_key_id)
);
CREATE INDEX IF NOT EXISTS wallets_api_key_id_idx ON wallets (api_key_id);
CREATE INDEX IF NOT EXISTS wallets_user_id_idx ON wallets (user_id);
CREATE TABLE IF NOT EXISTS wallet_transactions (
id TEXT PRIMARY KEY NOT NULL,
wallet_id TEXT NOT NULL,
category TEXT NOT NULL,
reason_code TEXT NOT NULL,
amount REAL NOT NULL,
balance_before REAL NOT NULL,
balance_after REAL NOT NULL,
recharge_balance_before REAL NOT NULL,
recharge_balance_after REAL NOT NULL,
gift_balance_before REAL NOT NULL,
gift_balance_after REAL NOT NULL,
link_type TEXT,
link_id TEXT,
operator_id TEXT,
description TEXT,
created_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_wallet_tx_wallet_created ON wallet_transactions (wallet_id, created_at);
CREATE INDEX IF NOT EXISTS idx_wallet_tx_category_created ON wallet_transactions (category, created_at);
CREATE INDEX IF NOT EXISTS idx_wallet_tx_reason_created ON wallet_transactions (reason_code, created_at);
CREATE INDEX IF NOT EXISTS idx_wallet_tx_link ON wallet_transactions (link_type, link_id);
CREATE INDEX IF NOT EXISTS ix_wallet_transactions_operator_id ON wallet_transactions (operator_id);
CREATE TABLE IF NOT EXISTS wallet_daily_usage_ledgers (
id TEXT PRIMARY KEY NOT NULL,
wallet_id TEXT NOT NULL,
billing_date TEXT NOT NULL,
billing_timezone TEXT NOT NULL,
total_cost_usd REAL NOT NULL DEFAULT 0,
total_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
first_finalized_at INTEGER,
last_finalized_at INTEGER,
aggregated_at INTEGER NOT NULL,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_wallet_daily_usage_wallet_date ON wallet_daily_usage_ledgers (wallet_id, billing_timezone, billing_date);
CREATE TABLE IF NOT EXISTS payment_orders (
id TEXT PRIMARY KEY NOT NULL,
order_no TEXT NOT NULL,
wallet_id TEXT NOT NULL,
user_id TEXT,
amount_usd REAL NOT NULL,
pay_amount REAL,
pay_currency TEXT,
exchange_rate REAL,
refunded_amount_usd REAL NOT NULL DEFAULT 0,
refundable_amount_usd REAL NOT NULL DEFAULT 0,
payment_method TEXT NOT NULL,
gateway_order_id TEXT,
gateway_response TEXT,
status TEXT NOT NULL DEFAULT 'pending',
created_at INTEGER NOT NULL,
paid_at INTEGER,
credited_at INTEGER,
expires_at INTEGER,
UNIQUE (order_no)
);
CREATE INDEX IF NOT EXISTS idx_payment_orders_wallet_created ON payment_orders (wallet_id, created_at);
CREATE INDEX IF NOT EXISTS idx_payment_orders_user_created ON payment_orders (user_id, created_at);
CREATE INDEX IF NOT EXISTS idx_payment_orders_status ON payment_orders (status);
CREATE INDEX IF NOT EXISTS idx_payment_orders_gateway_order_id ON payment_orders (gateway_order_id);
CREATE TABLE IF NOT EXISTS payment_callbacks (
id TEXT PRIMARY KEY NOT NULL,
payment_order_id TEXT,
payment_method TEXT NOT NULL,
callback_key TEXT NOT NULL,
order_no TEXT,
gateway_order_id TEXT,
payload_hash TEXT,
signature_valid INTEGER NOT NULL DEFAULT 0,
status TEXT NOT NULL DEFAULT 'received',
payload TEXT,
error_message TEXT,
created_at INTEGER NOT NULL,
processed_at INTEGER,
UNIQUE (callback_key)
);
CREATE INDEX IF NOT EXISTS idx_payment_callbacks_order ON payment_callbacks (order_no);
CREATE INDEX IF NOT EXISTS idx_payment_callbacks_gateway_order ON payment_callbacks (gateway_order_id);
CREATE INDEX IF NOT EXISTS idx_payment_callbacks_created ON payment_callbacks (created_at);
CREATE INDEX IF NOT EXISTS ix_payment_callbacks_payment_order_id ON payment_callbacks (payment_order_id);
CREATE TABLE IF NOT EXISTS refund_requests (
id TEXT PRIMARY KEY NOT NULL,
refund_no TEXT NOT NULL,
wallet_id TEXT NOT NULL,
user_id TEXT,
payment_order_id TEXT,
source_type TEXT NOT NULL,
source_id TEXT,
refund_mode TEXT NOT NULL,
amount_usd REAL NOT NULL,
status TEXT NOT NULL DEFAULT 'pending_approval',
reason TEXT,
requested_by TEXT,
approved_by TEXT,
processed_by TEXT,
gateway_refund_id TEXT,
payout_method TEXT,
payout_reference TEXT,
payout_proof TEXT,
failure_reason TEXT,
idempotency_key TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
processed_at INTEGER,
completed_at INTEGER,
UNIQUE (refund_no),
UNIQUE (idempotency_key)
);
CREATE INDEX IF NOT EXISTS idx_refund_wallet_created ON refund_requests (wallet_id, created_at);
CREATE INDEX IF NOT EXISTS idx_refund_user_created ON refund_requests (user_id, created_at);
CREATE INDEX IF NOT EXISTS idx_refund_status ON refund_requests (status);
CREATE INDEX IF NOT EXISTS ix_refund_requests_payment_order_id ON refund_requests (payment_order_id);
CREATE INDEX IF NOT EXISTS ix_refund_requests_requested_by ON refund_requests (requested_by);
CREATE INDEX IF NOT EXISTS ix_refund_requests_approved_by ON refund_requests (approved_by);
CREATE INDEX IF NOT EXISTS ix_refund_requests_processed_by ON refund_requests (processed_by);
CREATE TABLE IF NOT EXISTS redeem_code_batches (
id TEXT PRIMARY KEY NOT NULL,
name TEXT NOT NULL,
amount_usd REAL NOT NULL,
currency TEXT NOT NULL DEFAULT 'USD',
balance_bucket TEXT NOT NULL DEFAULT 'gift',
total_count INTEGER NOT NULL,
status TEXT NOT NULL DEFAULT 'active',
description TEXT,
created_by TEXT,
expires_at INTEGER,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_redeem_code_batches_status ON redeem_code_batches (status, created_at);
CREATE TABLE IF NOT EXISTS redeem_codes (
id TEXT PRIMARY KEY NOT NULL,
batch_id TEXT NOT NULL,
code_hash TEXT NOT NULL,
code_prefix TEXT NOT NULL,
code_suffix TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'active',
redeemed_by_user_id TEXT,
redeemed_wallet_id TEXT,
redeemed_payment_order_id TEXT,
redeemed_at INTEGER,
disabled_by TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (code_hash)
);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_batch_created ON redeem_codes (batch_id, created_at);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_status ON redeem_codes (status, updated_at);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_redeemed_user ON redeem_codes (redeemed_by_user_id, redeemed_at);
CREATE INDEX IF NOT EXISTS idx_redeem_codes_redeemed_order ON redeem_codes (redeemed_payment_order_id);

View File

@@ -0,0 +1,129 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS "usage" (
request_id TEXT PRIMARY KEY NOT NULL,
id TEXT,
user_id TEXT,
api_key_id TEXT,
provider_name TEXT NOT NULL DEFAULT 'unknown',
model TEXT NOT NULL DEFAULT 'unknown',
target_model TEXT,
provider_id TEXT,
provider_endpoint_id TEXT,
provider_api_key_id TEXT,
request_type TEXT,
api_format TEXT,
api_family TEXT,
endpoint_kind TEXT,
endpoint_api_format TEXT,
provider_api_family TEXT,
provider_endpoint_kind TEXT,
has_format_conversion INTEGER NOT NULL DEFAULT 0,
is_stream INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
input_output_total_tokens INTEGER NOT NULL DEFAULT 0,
total_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_input_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_input_tokens_5m INTEGER NOT NULL DEFAULT 0,
cache_creation_input_tokens_1h INTEGER NOT NULL DEFAULT 0,
cache_creation_ephemeral_5m_input_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_ephemeral_1h_input_tokens INTEGER NOT NULL DEFAULT 0,
cache_read_input_tokens INTEGER NOT NULL DEFAULT 0,
input_context_tokens INTEGER NOT NULL DEFAULT 0,
input_cost_usd REAL NOT NULL DEFAULT 0,
output_cost_usd REAL NOT NULL DEFAULT 0,
cache_cost_usd REAL NOT NULL DEFAULT 0,
cache_creation_cost_usd REAL NOT NULL DEFAULT 0,
cache_creation_cost_usd_5m REAL NOT NULL DEFAULT 0,
cache_creation_cost_usd_1h REAL NOT NULL DEFAULT 0,
cache_read_cost_usd REAL NOT NULL DEFAULT 0,
request_cost_usd REAL NOT NULL DEFAULT 0,
actual_input_cost_usd REAL NOT NULL DEFAULT 0,
actual_output_cost_usd REAL NOT NULL DEFAULT 0,
actual_cache_cost_usd REAL NOT NULL DEFAULT 0,
actual_cache_creation_cost_usd REAL NOT NULL DEFAULT 0,
actual_cache_creation_cost_usd_5m REAL NOT NULL DEFAULT 0,
actual_cache_creation_cost_usd_1h REAL NOT NULL DEFAULT 0,
actual_cache_read_cost_usd REAL NOT NULL DEFAULT 0,
actual_request_cost_usd REAL NOT NULL DEFAULT 0,
rate_multiplier REAL NOT NULL DEFAULT 1,
input_price_per_1m REAL,
output_price_per_1m REAL,
cache_creation_price_per_1m REAL,
cache_creation_price_per_1m_5m REAL,
cache_creation_price_per_1m_1h REAL,
cache_read_price_per_1m REAL,
price_per_request REAL,
status_code INTEGER,
error_message TEXT,
error_category TEXT,
response_time_ms INTEGER,
first_byte_time_ms INTEGER,
wallet_id TEXT,
status TEXT NOT NULL DEFAULT 'completed',
billing_status TEXT NOT NULL DEFAULT 'pending',
total_cost_usd REAL NOT NULL DEFAULT 0,
actual_total_cost_usd REAL NOT NULL DEFAULT 0,
request_headers TEXT,
request_body TEXT,
provider_request_headers TEXT,
provider_request_body TEXT,
response_headers TEXT,
response_body TEXT,
client_response_headers TEXT,
client_response_body TEXT,
request_body_compressed BLOB,
provider_request_body_compressed BLOB,
response_body_compressed BLOB,
client_response_body_compressed BLOB,
request_metadata TEXT,
created_at INTEGER,
candidate_id TEXT,
candidate_index INTEGER,
key_name TEXT,
username TEXT,
api_key_name TEXT,
planner_kind TEXT,
route_family TEXT,
route_kind TEXT,
execution_path TEXT,
local_execution_runtime_miss_reason TEXT,
wallet_balance_before REAL,
wallet_balance_after REAL,
wallet_recharge_balance_before REAL,
wallet_recharge_balance_after REAL,
wallet_gift_balance_before REAL,
wallet_gift_balance_after REAL,
finalized_at INTEGER,
created_at_unix_ms INTEGER NOT NULL DEFAULT 0,
updated_at_unix_secs INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX IF NOT EXISTS usage_api_key_id_idx ON "usage" (api_key_id);
CREATE INDEX IF NOT EXISTS usage_billing_status_idx ON "usage" (billing_status);
CREATE INDEX IF NOT EXISTS usage_created_at_idx ON "usage" (created_at_unix_ms);
CREATE INDEX IF NOT EXISTS usage_provider_api_key_id_idx ON "usage" (provider_api_key_id);
CREATE INDEX IF NOT EXISTS usage_provider_id_idx ON "usage" (provider_id);
CREATE INDEX IF NOT EXISTS usage_request_id_idx ON "usage" (request_id);
CREATE INDEX IF NOT EXISTS usage_user_id_idx ON "usage" (user_id);
CREATE INDEX IF NOT EXISTS usage_wallet_id_idx ON "usage" (wallet_id);
CREATE TABLE IF NOT EXISTS usage_settlement_snapshots (
request_id TEXT PRIMARY KEY NOT NULL,
billing_status TEXT NOT NULL,
wallet_id TEXT,
wallet_balance_before REAL,
wallet_balance_after REAL,
wallet_recharge_balance_before REAL,
wallet_recharge_balance_after REAL,
wallet_gift_balance_before REAL,
wallet_gift_balance_after REAL,
provider_monthly_used_usd REAL,
finalized_at INTEGER,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS usage_settlement_snapshots_billing_status_idx ON usage_settlement_snapshots (billing_status);
CREATE INDEX IF NOT EXISTS usage_settlement_snapshots_wallet_id_idx ON usage_settlement_snapshots (wallet_id);

View File

@@ -0,0 +1,223 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
CREATE TABLE IF NOT EXISTS stats_hourly (
id TEXT PRIMARY KEY NOT NULL,
hour_utc INTEGER NOT NULL,
total_requests INTEGER NOT NULL DEFAULT 0,
success_requests INTEGER NOT NULL DEFAULT 0,
error_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
actual_total_cost REAL NOT NULL DEFAULT 0,
avg_response_time_ms REAL NOT NULL DEFAULT 0,
is_complete INTEGER NOT NULL DEFAULT 0,
aggregated_at INTEGER,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (hour_utc)
);
CREATE TABLE IF NOT EXISTS stats_summary (
id TEXT PRIMARY KEY NOT NULL,
cutoff_date INTEGER NOT NULL,
all_time_requests INTEGER NOT NULL DEFAULT 0,
all_time_success_requests INTEGER NOT NULL DEFAULT 0,
all_time_error_requests INTEGER NOT NULL DEFAULT 0,
all_time_input_tokens INTEGER NOT NULL DEFAULT 0,
all_time_output_tokens INTEGER NOT NULL DEFAULT 0,
all_time_cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
all_time_cache_read_tokens INTEGER NOT NULL DEFAULT 0,
all_time_cost REAL NOT NULL DEFAULT 0,
all_time_actual_cost REAL NOT NULL DEFAULT 0,
total_users INTEGER NOT NULL DEFAULT 0,
active_users INTEGER NOT NULL DEFAULT 0,
total_api_keys INTEGER NOT NULL DEFAULT 0,
active_api_keys INTEGER NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS stats_hourly_user (
id TEXT PRIMARY KEY NOT NULL,
hour_utc INTEGER NOT NULL,
user_id TEXT NOT NULL,
total_requests INTEGER NOT NULL DEFAULT 0,
success_requests INTEGER NOT NULL DEFAULT 0,
error_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (hour_utc, user_id)
);
CREATE TABLE IF NOT EXISTS stats_hourly_user_model (
id TEXT PRIMARY KEY NOT NULL,
hour_utc INTEGER NOT NULL,
user_id TEXT NOT NULL,
model TEXT NOT NULL,
total_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (hour_utc, user_id, model)
);
CREATE TABLE IF NOT EXISTS user_model_usage_counts (
id TEXT PRIMARY KEY NOT NULL,
user_id TEXT NOT NULL,
model TEXT NOT NULL,
usage_count INTEGER NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (user_id, model)
);
CREATE INDEX IF NOT EXISTS idx_user_model_usage_user ON user_model_usage_counts (user_id);
CREATE INDEX IF NOT EXISTS idx_user_model_usage_model ON user_model_usage_counts (model);
CREATE TABLE IF NOT EXISTS stats_hourly_model (
id TEXT PRIMARY KEY NOT NULL,
hour_utc INTEGER NOT NULL,
model TEXT NOT NULL,
total_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
avg_response_time_ms REAL NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (hour_utc, model)
);
CREATE TABLE IF NOT EXISTS stats_hourly_provider (
id TEXT PRIMARY KEY NOT NULL,
hour_utc INTEGER NOT NULL,
provider_name TEXT NOT NULL,
total_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (hour_utc, provider_name)
);
CREATE TABLE IF NOT EXISTS stats_daily (
id TEXT PRIMARY KEY NOT NULL,
date INTEGER NOT NULL,
total_requests INTEGER NOT NULL DEFAULT 0,
success_requests INTEGER NOT NULL DEFAULT 0,
error_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
actual_total_cost REAL NOT NULL DEFAULT 0,
input_cost REAL NOT NULL DEFAULT 0,
output_cost REAL NOT NULL DEFAULT 0,
cache_creation_cost REAL NOT NULL DEFAULT 0,
cache_read_cost REAL NOT NULL DEFAULT 0,
avg_response_time_ms REAL NOT NULL DEFAULT 0,
fallback_count INTEGER NOT NULL DEFAULT 0,
unique_models INTEGER NOT NULL DEFAULT 0,
unique_providers INTEGER NOT NULL DEFAULT 0,
is_complete INTEGER NOT NULL DEFAULT 0,
aggregated_at INTEGER,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
p50_response_time_ms INTEGER,
p90_response_time_ms INTEGER,
p99_response_time_ms INTEGER,
p50_first_byte_time_ms INTEGER,
p90_first_byte_time_ms INTEGER,
p99_first_byte_time_ms INTEGER,
UNIQUE (date)
);
CREATE TABLE IF NOT EXISTS stats_daily_model (
id TEXT PRIMARY KEY NOT NULL,
date INTEGER NOT NULL,
model TEXT NOT NULL,
total_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
avg_response_time_ms REAL NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (date, model)
);
CREATE TABLE IF NOT EXISTS stats_daily_provider (
id TEXT PRIMARY KEY NOT NULL,
date INTEGER NOT NULL,
provider_name TEXT NOT NULL,
total_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (date, provider_name)
);
CREATE TABLE IF NOT EXISTS stats_daily_api_key (
id TEXT PRIMARY KEY NOT NULL,
api_key_id TEXT NOT NULL,
date INTEGER NOT NULL,
total_requests INTEGER NOT NULL DEFAULT 0,
success_requests INTEGER NOT NULL DEFAULT 0,
error_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
api_key_name TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (date, api_key_id)
);
CREATE TABLE IF NOT EXISTS stats_daily_error (
id TEXT PRIMARY KEY NOT NULL,
date INTEGER NOT NULL,
error_category TEXT NOT NULL,
provider_name TEXT,
model TEXT,
count INTEGER NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (date, error_category, provider_name, model)
);
CREATE TABLE IF NOT EXISTS stats_user_daily (
id TEXT PRIMARY KEY NOT NULL,
user_id TEXT NOT NULL,
date INTEGER NOT NULL,
total_requests INTEGER NOT NULL DEFAULT 0,
success_requests INTEGER NOT NULL DEFAULT 0,
error_requests INTEGER NOT NULL DEFAULT 0,
input_tokens INTEGER NOT NULL DEFAULT 0,
output_tokens INTEGER NOT NULL DEFAULT 0,
cache_creation_tokens INTEGER NOT NULL DEFAULT 0,
cache_read_tokens INTEGER NOT NULL DEFAULT 0,
total_cost REAL NOT NULL DEFAULT 0,
username TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
UNIQUE (date, user_id)
);

View File

@@ -0,0 +1,10 @@
-- Generated by aether-data-schema from schema/logical/*.toml.
-- Do not edit generated files directly; edit logical schema or explicit overrides instead.
001_identity.sql
002_provider_catalog.sql
003_auth_config.sql
004_proxy_nodes.sql
005_wallet_billing.sql
006_usage.sql
007_stats.sql

View File

@@ -0,0 +1,761 @@
[table.users]
domain = "identity"
order = 10
primary_key = ["id"]
[[table.users.columns]]
name = "id"
type = "text_id"
length = 64
[[table.users.columns]]
name = "external_id"
type = "text"
length = 255
nullable = true
[[table.users.columns]]
name = "email"
type = "text"
length = 320
nullable = true
[[table.users.columns]]
name = "username"
type = "text"
length = 255
nullable = true
[[table.users.columns]]
name = "password_hash"
type = "text"
length = 255
nullable = true
[[table.users.columns]]
name = "role"
type = "text"
length = 64
nullable = true
[[table.users.columns]]
name = "auth_source"
type = "text"
length = 64
default = "local"
[[table.users.columns]]
name = "email_verified"
type = "bool"
default = false
[[table.users.columns]]
name = "is_active"
type = "bool"
default = true
[[table.users.columns]]
name = "is_deleted"
type = "bool"
default = false
[[table.users.columns]]
name = "allowed_models"
type = "json"
nullable = true
[[table.users.columns]]
name = "allowed_providers"
type = "json"
nullable = true
[[table.users.columns]]
name = "allowed_api_formats"
type = "json"
nullable = true
[[table.users.columns]]
name = "model_capability_settings"
type = "json"
nullable = true
[[table.users.columns]]
name = "rate_limit"
type = "int32"
nullable = true
[[table.users.columns]]
name = "metadata"
type = "json"
nullable = true
[[table.users.columns]]
name = "created_at"
type = "unix_seconds"
[[table.users.columns]]
name = "updated_at"
type = "unix_seconds"
[[table.users.columns]]
name = "last_login_at"
type = "unix_seconds"
nullable = true
[[table.users.columns]]
name = "ldap_dn"
type = "text"
length = 1024
nullable = true
[[table.users.columns]]
name = "ldap_username"
type = "text"
length = 255
nullable = true
[[table.users.uniques]]
name = "users_email_key"
columns = ["email"]
[[table.users.uniques]]
name = "users_username_key"
columns = ["username"]
[table.api_keys]
domain = "identity"
order = 20
primary_key = ["id"]
[[table.api_keys.columns]]
name = "id"
type = "text_id"
length = 64
[[table.api_keys.columns]]
name = "user_id"
type = "text_id"
length = 64
[[table.api_keys.columns]]
name = "key_hash"
type = "text"
length = 255
[[table.api_keys.columns]]
name = "key_encrypted"
type = "long_text"
nullable = true
[[table.api_keys.columns]]
name = "name"
type = "text"
length = 255
nullable = true
[[table.api_keys.columns]]
name = "key_prefix"
type = "text"
length = 64
nullable = true
[[table.api_keys.columns]]
name = "status"
type = "text"
length = 64
default = "active"
[[table.api_keys.columns]]
name = "allowed_models"
type = "json"
nullable = true
[[table.api_keys.columns]]
name = "allowed_providers"
type = "json"
nullable = true
[[table.api_keys.columns]]
name = "allowed_api_formats"
type = "json"
nullable = true
[[table.api_keys.columns]]
name = "rate_limit"
type = "int32"
nullable = true
default = 100
[[table.api_keys.columns]]
name = "concurrent_limit"
type = "int32"
nullable = true
[[table.api_keys.columns]]
name = "force_capabilities"
type = "json"
nullable = true
[[table.api_keys.columns]]
name = "is_active"
type = "bool"
default = true
[[table.api_keys.columns]]
name = "is_locked"
type = "bool"
default = false
[[table.api_keys.columns]]
name = "is_standalone"
type = "bool"
default = false
[[table.api_keys.columns]]
name = "auto_delete_on_expiry"
type = "bool"
default = false
[[table.api_keys.columns]]
name = "total_requests"
type = "int64"
default = 0
[[table.api_keys.columns]]
name = "total_tokens"
type = "int64"
default = 0
[[table.api_keys.columns]]
name = "total_cost_usd"
type = "float64"
default = 0
[[table.api_keys.columns]]
name = "metadata"
type = "json"
nullable = true
[[table.api_keys.columns]]
name = "expires_at"
type = "unix_seconds"
nullable = true
[[table.api_keys.columns]]
name = "last_used_at"
type = "unix_seconds"
nullable = true
[[table.api_keys.columns]]
name = "created_at"
type = "unix_seconds"
[[table.api_keys.columns]]
name = "updated_at"
type = "unix_seconds"
[[table.api_keys.uniques]]
name = "api_keys_key_hash_key"
columns = ["key_hash"]
[[table.api_keys.indexes]]
name = "api_keys_user_id_idx"
columns = ["user_id"]
[table.audit_logs]
domain = "identity"
order = 30
primary_key = ["id"]
[[table.audit_logs.columns]]
name = "id"
type = "text_id"
length = 64
[[table.audit_logs.columns]]
name = "event_type"
type = "text"
length = 64
[[table.audit_logs.columns]]
name = "user_id"
type = "text_id"
length = 64
nullable = true
[[table.audit_logs.columns]]
name = "api_key_id"
type = "text_id"
length = 64
nullable = true
[[table.audit_logs.columns]]
name = "description"
type = "long_text"
[[table.audit_logs.columns]]
name = "ip_address"
type = "text"
length = 64
nullable = true
[[table.audit_logs.columns]]
name = "user_agent"
type = "text"
length = 512
nullable = true
[[table.audit_logs.columns]]
name = "request_id"
type = "text"
length = 128
nullable = true
[[table.audit_logs.columns]]
name = "event_metadata"
type = "json"
nullable = true
[[table.audit_logs.columns]]
name = "status_code"
type = "int32"
nullable = true
[[table.audit_logs.columns]]
name = "error_message"
type = "long_text"
nullable = true
[[table.audit_logs.columns]]
name = "created_at"
type = "unix_seconds"
[[table.audit_logs.indexes]]
name = "audit_logs_created_at_idx"
columns = ["created_at"]
[[table.audit_logs.indexes]]
name = "audit_logs_event_type_idx"
columns = ["event_type"]
[[table.audit_logs.indexes]]
name = "audit_logs_request_id_idx"
columns = ["request_id"]
[[table.audit_logs.indexes]]
name = "audit_logs_user_id_idx"
columns = ["user_id"]
[table.announcements]
domain = "identity"
order = 40
primary_key = ["id"]
[[table.announcements.columns]]
name = "id"
type = "text_id"
length = 64
[[table.announcements.columns]]
name = "title"
type = "text"
length = 200
[[table.announcements.columns]]
name = "content"
type = "long_text"
[[table.announcements.columns]]
name = "type"
type = "text"
length = 32
default = "info"
[[table.announcements.columns]]
name = "priority"
type = "int32"
default = 0
[[table.announcements.columns]]
name = "author_id"
type = "text_id"
length = 64
nullable = true
[[table.announcements.columns]]
name = "is_active"
type = "bool"
default = true
[[table.announcements.columns]]
name = "is_pinned"
type = "bool"
default = false
[[table.announcements.columns]]
name = "start_time"
type = "unix_seconds"
nullable = true
[[table.announcements.columns]]
name = "end_time"
type = "unix_seconds"
nullable = true
[[table.announcements.columns]]
name = "created_at"
type = "unix_seconds"
[[table.announcements.columns]]
name = "updated_at"
type = "unix_seconds"
[[table.announcements.indexes]]
name = "announcements_author_id_idx"
columns = ["author_id"]
[[table.announcements.indexes]]
name = "announcements_created_at_idx"
columns = ["created_at"]
[[table.announcements.indexes]]
name = "announcements_is_active_idx"
columns = ["is_active"]
[table.announcement_reads]
domain = "identity"
order = 50
primary_key = ["id"]
[[table.announcement_reads.columns]]
name = "id"
type = "text_id"
length = 64
[[table.announcement_reads.columns]]
name = "user_id"
type = "text_id"
length = 64
[[table.announcement_reads.columns]]
name = "announcement_id"
type = "text_id"
length = 64
[[table.announcement_reads.columns]]
name = "read_at"
type = "unix_seconds"
[[table.announcement_reads.uniques]]
name = "uq_user_announcement"
columns = ["user_id", "announcement_id"]
[[table.announcement_reads.indexes]]
name = "announcement_reads_announcement_id_idx"
columns = ["announcement_id"]
[[table.announcement_reads.indexes]]
name = "announcement_reads_user_id_idx"
columns = ["user_id"]
[table.management_tokens]
domain = "identity"
order = 60
primary_key = ["id"]
[[table.management_tokens.columns]]
name = "id"
type = "text_id"
length = 64
[[table.management_tokens.columns]]
name = "user_id"
type = "text_id"
length = 64
[[table.management_tokens.columns]]
name = "name"
type = "text"
length = 255
[[table.management_tokens.columns]]
name = "description"
type = "long_text"
nullable = true
[[table.management_tokens.columns]]
name = "token_hash"
type = "text"
length = 255
[[table.management_tokens.columns]]
name = "token_prefix"
type = "text"
length = 64
nullable = true
[[table.management_tokens.columns]]
name = "allowed_ips"
type = "json"
nullable = true
[[table.management_tokens.columns]]
name = "expires_at"
type = "unix_seconds"
nullable = true
[[table.management_tokens.columns]]
name = "last_used_at"
type = "unix_seconds"
nullable = true
[[table.management_tokens.columns]]
name = "last_used_ip"
type = "text"
length = 255
nullable = true
[[table.management_tokens.columns]]
name = "usage_count"
type = "int64"
default = 0
[[table.management_tokens.columns]]
name = "is_active"
type = "bool"
default = true
[[table.management_tokens.columns]]
name = "created_at"
type = "unix_seconds"
[[table.management_tokens.columns]]
name = "updated_at"
type = "unix_seconds"
[[table.management_tokens.uniques]]
name = "management_tokens_token_hash_key"
columns = ["token_hash"]
[[table.management_tokens.uniques]]
name = "uq_management_tokens_user_name"
columns = ["user_id", "name"]
[[table.management_tokens.indexes]]
name = "management_tokens_user_id_idx"
columns = ["user_id"]
[table.user_preferences]
domain = "identity"
order = 70
primary_key = ["id"]
[[table.user_preferences.columns]]
name = "id"
type = "text_id"
length = 64
[[table.user_preferences.columns]]
name = "user_id"
type = "text_id"
length = 64
[[table.user_preferences.columns]]
name = "avatar_url"
type = "text"
length = 500
nullable = true
[[table.user_preferences.columns]]
name = "bio"
type = "long_text"
nullable = true
[[table.user_preferences.columns]]
name = "default_provider_id"
type = "text_id"
length = 64
nullable = true
[[table.user_preferences.columns]]
name = "theme"
type = "text"
length = 20
default = "light"
[[table.user_preferences.columns]]
name = "language"
type = "text"
length = 10
default = "zh-CN"
[[table.user_preferences.columns]]
name = "timezone"
type = "text"
length = 50
default = "Asia/Shanghai"
[[table.user_preferences.columns]]
name = "email_notifications"
type = "bool"
default = true
[[table.user_preferences.columns]]
name = "usage_alerts"
type = "bool"
default = true
[[table.user_preferences.columns]]
name = "announcement_notifications"
type = "bool"
default = true
[[table.user_preferences.columns]]
name = "created_at"
type = "unix_seconds"
[[table.user_preferences.columns]]
name = "updated_at"
type = "unix_seconds"
[[table.user_preferences.uniques]]
name = "user_preferences_user_id_key"
columns = ["user_id"]
[[table.user_preferences.indexes]]
name = "user_preferences_default_provider_id_idx"
columns = ["default_provider_id"]
[[table.user_preferences.indexes]]
name = "user_preferences_user_id_idx"
columns = ["user_id"]
[table.user_sessions]
domain = "identity"
order = 80
primary_key = ["id"]
[[table.user_sessions.columns]]
name = "id"
type = "text_id"
length = 64
[[table.user_sessions.columns]]
name = "user_id"
type = "text_id"
length = 64
[[table.user_sessions.columns]]
name = "client_device_id"
type = "text"
length = 128
[[table.user_sessions.columns]]
name = "device_label"
type = "text"
length = 120
nullable = true
[[table.user_sessions.columns]]
name = "device_type"
type = "text"
length = 20
default = "unknown"
[[table.user_sessions.columns]]
name = "browser_name"
type = "text"
length = 50
nullable = true
[[table.user_sessions.columns]]
name = "browser_version"
type = "text"
length = 50
nullable = true
[[table.user_sessions.columns]]
name = "os_name"
type = "text"
length = 50
nullable = true
[[table.user_sessions.columns]]
name = "os_version"
type = "text"
length = 50
nullable = true
[[table.user_sessions.columns]]
name = "device_model"
type = "text"
length = 100
nullable = true
[[table.user_sessions.columns]]
name = "ip_address"
type = "text"
length = 45
nullable = true
[[table.user_sessions.columns]]
name = "user_agent"
type = "text"
length = 1000
nullable = true
[[table.user_sessions.columns]]
name = "client_hints"
type = "json"
nullable = true
[[table.user_sessions.columns]]
name = "refresh_token_hash"
type = "text"
length = 64
[[table.user_sessions.columns]]
name = "prev_refresh_token_hash"
type = "text"
length = 64
nullable = true
[[table.user_sessions.columns]]
name = "rotated_at"
type = "unix_seconds"
nullable = true
[[table.user_sessions.columns]]
name = "last_seen_at"
type = "unix_seconds"
[[table.user_sessions.columns]]
name = "expires_at"
type = "unix_seconds"
[[table.user_sessions.columns]]
name = "revoked_at"
type = "unix_seconds"
nullable = true
[[table.user_sessions.columns]]
name = "revoke_reason"
type = "text"
length = 100
nullable = true
[[table.user_sessions.columns]]
name = "created_at"
type = "unix_seconds"
[[table.user_sessions.columns]]
name = "updated_at"
type = "unix_seconds"
[[table.user_sessions.indexes]]
name = "user_sessions_user_active_idx"
columns = ["user_id", "revoked_at", "expires_at"]
[[table.user_sessions.indexes]]
name = "user_sessions_user_device_idx"
columns = ["user_id", "client_device_id"]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,297 @@
[table.system_configs]
domain = "auth_config"
order = 10
primary_key = ["id"]
[[table.system_configs.columns]]
name = "id"
type = "text_id"
length = 64
[[table.system_configs.columns]]
name = "key"
type = "text"
length = 255
[[table.system_configs.columns]]
name = "value"
type = "long_text"
[[table.system_configs.columns]]
name = "description"
type = "long_text"
nullable = true
[[table.system_configs.columns]]
name = "created_at"
type = "unix_seconds"
[[table.system_configs.columns]]
name = "updated_at"
type = "unix_seconds"
[[table.system_configs.uniques]]
name = "system_configs_key_key"
columns = ["key"]
[table.auth_modules]
domain = "auth_config"
order = 20
primary_key = ["id"]
[[table.auth_modules.columns]]
name = "id"
type = "text_id"
length = 64
[[table.auth_modules.columns]]
name = "module_type"
type = "text"
length = 128
[[table.auth_modules.columns]]
name = "enabled"
type = "bool"
default = true
[[table.auth_modules.columns]]
name = "config"
type = "json"
[[table.auth_modules.columns]]
name = "created_at"
type = "unix_seconds"
[[table.auth_modules.columns]]
name = "updated_at"
type = "unix_seconds"
[[table.auth_modules.uniques]]
name = "auth_modules_module_type_key"
columns = ["module_type"]
[table.oauth_providers]
domain = "auth_config"
order = 30
primary_key = ["provider_type"]
[[table.oauth_providers.columns]]
name = "provider_type"
type = "text"
length = 64
[[table.oauth_providers.columns]]
name = "display_name"
type = "text"
length = 255
[[table.oauth_providers.columns]]
name = "client_id"
type = "long_text"
[[table.oauth_providers.columns]]
name = "client_secret_encrypted"
type = "long_text"
nullable = true
[[table.oauth_providers.columns]]
name = "authorization_url_override"
type = "text"
length = 500
nullable = true
[[table.oauth_providers.columns]]
name = "token_url_override"
type = "text"
length = 500
nullable = true
[[table.oauth_providers.columns]]
name = "userinfo_url_override"
type = "text"
length = 500
nullable = true
[[table.oauth_providers.columns]]
name = "scopes"
type = "json"
nullable = true
[[table.oauth_providers.columns]]
name = "redirect_uri"
type = "text"
length = 500
[[table.oauth_providers.columns]]
name = "frontend_callback_url"
type = "text"
length = 500
[[table.oauth_providers.columns]]
name = "attribute_mapping"
type = "json"
nullable = true
[[table.oauth_providers.columns]]
name = "extra_config"
type = "json"
nullable = true
[[table.oauth_providers.columns]]
name = "is_enabled"
type = "bool"
default = false
[[table.oauth_providers.columns]]
name = "created_at"
type = "unix_seconds"
[[table.oauth_providers.columns]]
name = "updated_at"
type = "unix_seconds"
[table.ldap_configs]
domain = "auth_config"
order = 40
primary_key = ["id"]
[[table.ldap_configs.columns]]
name = "id"
type = "int64"
auto_increment = true
[[table.ldap_configs.columns]]
name = "server_url"
type = "text"
length = 255
[[table.ldap_configs.columns]]
name = "bind_dn"
type = "long_text"
[[table.ldap_configs.columns]]
name = "bind_password_encrypted"
type = "long_text"
nullable = true
[[table.ldap_configs.columns]]
name = "base_dn"
type = "long_text"
[[table.ldap_configs.columns]]
name = "user_search_filter"
type = "long_text"
default = "(uid={username})"
[[table.ldap_configs.columns]]
name = "username_attr"
type = "text"
length = 50
default = "uid"
[[table.ldap_configs.columns]]
name = "email_attr"
type = "text"
length = 50
default = "mail"
[[table.ldap_configs.columns]]
name = "display_name_attr"
type = "text"
length = 50
default = "cn"
[[table.ldap_configs.columns]]
name = "is_enabled"
type = "bool"
default = false
[[table.ldap_configs.columns]]
name = "is_exclusive"
type = "bool"
default = false
[[table.ldap_configs.columns]]
name = "use_starttls"
type = "bool"
default = false
[[table.ldap_configs.columns]]
name = "connect_timeout"
type = "int32"
default = 10
[[table.ldap_configs.columns]]
name = "created_at"
type = "unix_seconds"
[[table.ldap_configs.columns]]
name = "updated_at"
type = "unix_seconds"
[table.user_oauth_links]
domain = "auth_config"
order = 50
primary_key = ["id"]
[[table.user_oauth_links.columns]]
name = "id"
type = "text_id"
length = 64
[[table.user_oauth_links.columns]]
name = "user_id"
type = "text_id"
length = 64
[[table.user_oauth_links.columns]]
name = "provider_type"
type = "text"
length = 64
[[table.user_oauth_links.columns]]
name = "provider_user_id"
type = "text"
length = 255
[[table.user_oauth_links.columns]]
name = "provider_username"
type = "text"
length = 255
nullable = true
[[table.user_oauth_links.columns]]
name = "provider_email"
type = "text"
length = 255
nullable = true
[[table.user_oauth_links.columns]]
name = "extra_data"
type = "json"
nullable = true
[[table.user_oauth_links.columns]]
name = "linked_at"
type = "unix_seconds"
[[table.user_oauth_links.columns]]
name = "last_login_at"
type = "unix_seconds"
nullable = true
[[table.user_oauth_links.indexes]]
name = "user_oauth_links_provider_type_idx"
columns = ["provider_type"]
[[table.user_oauth_links.indexes]]
name = "user_oauth_links_user_id_idx"
columns = ["user_id"]
[[table.user_oauth_links.uniques]]
name = "uq_user_oauth_links_provider_user"
columns = ["provider_type", "provider_user_id"]
[[table.user_oauth_links.uniques]]
name = "uq_user_oauth_links_user_provider"
columns = ["user_id", "provider_type"]

Some files were not shown because too many files have changed in this diff Show More