refactor: purge Node.js, Rust is the one true backend
- Moved boosapi-rs/* to repo root - Deleted all Node.js source (src/server/, src/web/, scripts/) - Deleted node_modules, package.json, tsconfig, vite.config - Updated .gitignore and AGENTS.md for Rust-only stack - Fixed static file path for frontend dist/web/ - Dockerfile stays the same (already Rust-only) - Kept dist/web/ for Rust static serving
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
use sqlx::sqlite::{SqlitePool, SqlitePoolOptions};
|
||||
|
||||
pub mod models;
|
||||
pub mod queries;
|
||||
|
||||
pub async fn create_pool(database_url: &str, max_connections: u32) -> anyhow::Result<SqlitePool> {
|
||||
let pool = SqlitePoolOptions::new()
|
||||
.max_connections(max_connections)
|
||||
.connect(database_url)
|
||||
.await?;
|
||||
Ok(pool)
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
|
||||
/// Represents an account bound to a site.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
pub struct Account {
|
||||
pub id: i64,
|
||||
pub site_id: i64,
|
||||
pub username: Option<String>,
|
||||
pub access_token: String,
|
||||
pub api_token: Option<String>,
|
||||
pub balance: Option<f64>,
|
||||
pub balance_used: Option<f64>,
|
||||
pub quota: Option<f64>,
|
||||
pub unit_cost: Option<f64>,
|
||||
pub value_score: Option<f64>,
|
||||
pub status: String,
|
||||
pub checkin_enabled: Option<bool>,
|
||||
pub last_checkin_at: Option<String>,
|
||||
pub last_balance_refresh: Option<String>,
|
||||
pub extra_config: Option<String>,
|
||||
pub is_pinned: Option<bool>,
|
||||
pub sort_order: Option<i64>,
|
||||
pub oauth_provider: Option<String>,
|
||||
pub oauth_account_key: Option<String>,
|
||||
pub oauth_project_id: Option<String>,
|
||||
pub created_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
}
|
||||
|
||||
/// Represents an account token (from account_tokens table).
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
pub struct AccountToken {
|
||||
pub id: i64,
|
||||
pub account_id: i64,
|
||||
pub name: String,
|
||||
pub token: String,
|
||||
pub source: Option<String>,
|
||||
pub token_group: Option<String>,
|
||||
pub value_status: String,
|
||||
pub enabled: Option<bool>,
|
||||
pub is_default: Option<bool>,
|
||||
pub created_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
|
||||
/// Background task for tracking async operations (deployments, syncs, etc.)
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
pub struct BackgroundTask {
|
||||
pub id: String,
|
||||
pub task_type: String,
|
||||
pub title: String,
|
||||
pub status: String,
|
||||
pub message: Option<String>,
|
||||
pub error: Option<String>,
|
||||
pub dedupe_key: Option<String>,
|
||||
pub success_title: Option<String>,
|
||||
pub failure_title: Option<String>,
|
||||
pub notify_on_success: Option<bool>,
|
||||
pub notify_on_failure: Option<bool>,
|
||||
pub result_json: Option<String>,
|
||||
pub progress: Option<i64>,
|
||||
pub progress_total: Option<i64>,
|
||||
pub created_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
pub started_at: Option<String>,
|
||||
pub finished_at: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
|
||||
/// Represents a downstream API key for external consumers.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
pub struct DownstreamApiKey {
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
pub key: String,
|
||||
pub description: Option<String>,
|
||||
pub group_name: Option<String>,
|
||||
pub tags: Option<String>,
|
||||
pub enabled: Option<bool>,
|
||||
pub expires_at: Option<String>,
|
||||
pub max_cost: Option<f64>,
|
||||
pub used_cost: Option<f64>,
|
||||
pub max_requests: Option<i64>,
|
||||
pub used_requests: Option<i64>,
|
||||
pub supported_models: Option<String>,
|
||||
pub allowed_route_ids: Option<String>,
|
||||
pub site_weight_multipliers: Option<String>,
|
||||
pub excluded_site_ids: Option<String>,
|
||||
pub excluded_credential_refs: Option<String>,
|
||||
pub last_used_at: Option<String>,
|
||||
pub user_id: Option<i64>,
|
||||
pub created_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
|
||||
/// System event for admin notifications.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
pub struct Event {
|
||||
pub id: i64,
|
||||
#[sqlx(rename = "type")]
|
||||
pub event_type: String,
|
||||
pub title: String,
|
||||
pub message: Option<String>,
|
||||
pub level: Option<String>,
|
||||
#[sqlx(rename = "read")]
|
||||
pub is_read: Option<bool>,
|
||||
pub related_id: Option<i64>,
|
||||
pub related_type: Option<String>,
|
||||
pub created_at: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// Database models
|
||||
|
||||
pub mod account;
|
||||
pub mod background_task;
|
||||
pub mod downstream_api_key;
|
||||
pub mod event;
|
||||
pub mod organization;
|
||||
pub mod route_channel;
|
||||
pub mod setting;
|
||||
pub mod site;
|
||||
pub mod site_announcement;
|
||||
pub mod token_route;
|
||||
pub mod user;
|
||||
@@ -0,0 +1,39 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
|
||||
/// Organization for multi-tenant setup.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
pub struct Organization {
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
pub slug: String,
|
||||
pub plan: Option<String>,
|
||||
pub status: Option<String>,
|
||||
pub created_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
}
|
||||
|
||||
/// Member of an organization.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
pub struct OrganizationMember {
|
||||
pub id: i64,
|
||||
pub org_id: i64,
|
||||
pub user_id: i64,
|
||||
pub role: Option<String>,
|
||||
pub status: Option<String>,
|
||||
pub joined_at: Option<String>,
|
||||
}
|
||||
|
||||
/// Invitation to join an organization.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
pub struct Invitation {
|
||||
pub id: i64,
|
||||
pub org_id: i64,
|
||||
pub email: String,
|
||||
pub token: String,
|
||||
pub role: Option<String>,
|
||||
pub invited_by: Option<i64>,
|
||||
pub status: Option<String>,
|
||||
pub expires_at: Option<String>,
|
||||
pub created_at: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
|
||||
/// Represents a route channel linking routes, accounts, and tokens.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
pub struct RouteChannel {
|
||||
pub id: i64,
|
||||
pub route_id: i64,
|
||||
pub account_id: i64,
|
||||
pub token_id: Option<i64>,
|
||||
pub oauth_route_unit_id: Option<i64>,
|
||||
pub source_model: Option<String>,
|
||||
pub priority: Option<i64>,
|
||||
pub weight: Option<i64>,
|
||||
pub enabled: Option<bool>,
|
||||
pub manual_override: Option<bool>,
|
||||
pub success_count: Option<i64>,
|
||||
pub fail_count: Option<i64>,
|
||||
pub total_latency_ms: Option<i64>,
|
||||
pub total_cost: Option<f64>,
|
||||
pub last_used_at: Option<String>,
|
||||
pub last_selected_at: Option<String>,
|
||||
pub last_fail_at: Option<String>,
|
||||
pub consecutive_fail_count: i64,
|
||||
pub cooldown_level: i64,
|
||||
pub cooldown_until: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
|
||||
/// Represents a key-value setting.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
pub struct Setting {
|
||||
pub key: String,
|
||||
pub value: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
|
||||
/// Represents a site (AI provider endpoint).
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
pub struct Site {
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
pub url: String,
|
||||
pub platform: String,
|
||||
pub status: String,
|
||||
pub api_key: Option<String>,
|
||||
pub proxy_url: Option<String>,
|
||||
pub use_system_proxy: Option<bool>,
|
||||
pub custom_headers: Option<String>,
|
||||
pub external_checkin_url: Option<String>,
|
||||
pub global_weight: Option<f64>,
|
||||
pub post_refresh_probe_enabled: Option<bool>,
|
||||
pub post_refresh_probe_model: Option<String>,
|
||||
pub post_refresh_probe_scope: Option<String>,
|
||||
pub post_refresh_probe_latency_threshold_ms: Option<i64>,
|
||||
pub is_pinned: Option<bool>,
|
||||
pub sort_order: Option<i64>,
|
||||
pub created_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
|
||||
/// Site-level announcements (notifications from upstream providers).
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
pub struct SiteAnnouncement {
|
||||
pub id: i64,
|
||||
pub site_id: i64,
|
||||
pub platform: String,
|
||||
pub source_key: String,
|
||||
pub title: String,
|
||||
pub content: String,
|
||||
pub level: Option<String>,
|
||||
pub source_url: Option<String>,
|
||||
pub starts_at: Option<String>,
|
||||
pub ends_at: Option<String>,
|
||||
pub upstream_created_at: Option<String>,
|
||||
pub upstream_updated_at: Option<String>,
|
||||
pub first_seen_at: Option<String>,
|
||||
pub last_seen_at: Option<String>,
|
||||
pub read_at: Option<String>,
|
||||
pub dismissed_at: Option<String>,
|
||||
pub raw_payload: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
|
||||
/// Represents a token route (model routing rule).
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
pub struct TokenRoute {
|
||||
pub id: i64,
|
||||
pub model_pattern: String,
|
||||
pub model_mapping: Option<String>,
|
||||
pub display_name: Option<String>,
|
||||
pub display_icon: Option<String>,
|
||||
pub decision_snapshot: Option<String>,
|
||||
pub decision_refreshed_at: Option<String>,
|
||||
pub routing_strategy: Option<String>,
|
||||
pub route_mode: Option<String>,
|
||||
pub enabled: Option<bool>,
|
||||
pub created_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sqlx::FromRow;
|
||||
|
||||
/// A platform user (admin or regular).
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, FromRow)]
|
||||
pub struct User {
|
||||
pub id: i64,
|
||||
pub username: String,
|
||||
pub email: String,
|
||||
#[serde(skip_serializing)]
|
||||
pub password_hash: String,
|
||||
pub role: String,
|
||||
pub status: String,
|
||||
pub created_at: Option<String>,
|
||||
pub updated_at: Option<String>,
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
use crate::{
|
||||
db::models::{downstream_api_key::DownstreamApiKey, user::User},
|
||||
error::AppResult,
|
||||
};
|
||||
use sqlx::SqlitePool;
|
||||
|
||||
pub async fn find_user_by_id(db: &SqlitePool, id: i64) -> AppResult<Option<User>> {
|
||||
sqlx::query_as("SELECT * FROM users WHERE id = ?")
|
||||
.bind(id)
|
||||
.fetch_optional(db)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn find_user_by_email(db: &SqlitePool, email: &str) -> AppResult<Option<User>> {
|
||||
sqlx::query_as("SELECT * FROM users WHERE email = ?")
|
||||
.bind(email)
|
||||
.fetch_optional(db)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn list_user_api_keys(db: &SqlitePool, user_id: i64) -> AppResult<Vec<DownstreamApiKey>> {
|
||||
sqlx::query_as("SELECT * FROM downstream_api_keys WHERE user_id = ? ORDER BY created_at DESC")
|
||||
.bind(user_id)
|
||||
.fetch_all(db)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn find_downstream_key_by_token(
|
||||
db: &SqlitePool,
|
||||
token: &str,
|
||||
) -> AppResult<Option<DownstreamApiKey>> {
|
||||
sqlx::query_as("SELECT * FROM downstream_api_keys WHERE key = ?")
|
||||
.bind(token)
|
||||
.fetch_optional(db)
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
Reference in New Issue
Block a user