pub mod api;
pub mod auth;
pub mod config;
pub mod dashboard;
pub mod database;
pub mod error;
pub mod middleware;
pub mod observability;
pub mod storage;
pub mod billing;
pub mod templates;
pub mod websocket;
pub mod state;
pub mod query_builder;
pub mod monitoring;
pub mod teams;
pub mod ai_assistant;
pub mod ai_engine;
use std::net::SocketAddr;
use std::sync::Arc;
use axum::Router;
use tower::ServiceBuilder;
use tower_http::{
services::ServeDir,
trace::TraceLayer,
compression::CompressionLayer,
cors::CorsLayer,
};
pub use config::ConsoleConfig;
pub use error::{ConsoleError, Result};
pub use state::AppState;
#[derive(Clone)]
pub struct Console {
state: Arc<AppState>,
config: ConsoleConfig,
}
impl Console {
pub async fn new(config: ConsoleConfig) -> Result<Self> {
let state = Arc::new(AppState::new(&config).await?);
Ok(Self { state, config })
}
pub fn router(&self) -> Router {
Router::new()
.nest("/api", api::routes(self.state.clone()))
.nest("/dashboard", dashboard::routes(self.state.clone()))
.nest("/databases", database::routes(self.state.clone()))
.nest("/storage", storage::routes(self.state.clone()))
.nest("/observability", observability::routes(self.state.clone()))
.nest("/billing", billing::routes(self.state.clone()))
.nest("/query-builder", query_builder::router(self.state.clone()))
.nest("/monitoring", monitoring::router(self.state.clone()))
.nest("/teams", teams::router(self.state.clone()))
.nest("/ai-assistant", ai_assistant::router(self.state.clone()))
.nest("/ws", websocket::routes(self.state.clone()))
.nest_service("/static", ServeDir::new("static"))
.fallback(dashboard::index)
.layer(
ServiceBuilder::new()
.layer(TraceLayer::new_for_http())
.layer(CompressionLayer::new())
.layer(CorsLayer::permissive())
.layer(middleware::auth::AuthLayer::new(self.state.clone()))
.layer(middleware::rate_limit::RateLimitLayer::new())
)
}
pub async fn serve(self, addr: impl Into<SocketAddr>) -> Result<()> {
let addr = addr.into();
let router = self.router();
tracing::info!("🖥️ AVL Console starting on http://{}", addr);
tracing::info!("📊 Dashboard: http://{}/dashboard", addr);
tracing::info!("🗄️ AvilaDB Explorer: http://{}/databases", addr);
tracing::info!("💾 Storage Browser: http://{}/storage", addr);
tracing::info!("📈 Observability: http://{}/observability", addr);
tracing::info!("🎨 Query Builder: http://{}/query-builder", addr);
tracing::info!("🔬 Advanced Monitoring: http://{}/monitoring", addr);
tracing::info!("👥 Team Management: http://{}/teams", addr);
tracing::info!("🤖 AI Assistant: http://{}/ai-assistant", addr);
let listener = tokio::net::TcpListener::bind(addr)
.await
.map_err(|e| ConsoleError::Server(e.to_string()))?;
axum::serve(listener, router)
.await
.map_err(|e| ConsoleError::Server(e.to_string()))?;
Ok(())
}
pub fn state(&self) -> &Arc<AppState> {
&self.state
}
pub fn config(&self) -> &ConsoleConfig {
&self.config
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_console_creation() {
let config = ConsoleConfig::default();
let console = Console::new(config).await;
assert!(console.is_ok());
}
}