allsource_core/
api_v1.rs

1/// v1.0 API router with authentication and multi-tenancy
2use crate::auth::AuthManager;
3use crate::auth_api::*;
4use crate::middleware::{auth_middleware, rate_limit_middleware, AuthState, RateLimitState};
5use crate::rate_limit::RateLimiter;
6use crate::store::EventStore;
7use crate::tenant::TenantManager;
8use crate::tenant_api::*;
9use axum::{
10    middleware,
11    routing::{delete, get, post, put},
12    Router,
13};
14use std::sync::Arc;
15use tower_http::cors::{Any, CorsLayer};
16use tower_http::trace::TraceLayer;
17
18/// Unified application state for all handlers
19#[derive(Clone)]
20pub struct AppState {
21    pub store: Arc<EventStore>,
22    pub auth_manager: Arc<AuthManager>,
23    pub tenant_manager: Arc<TenantManager>,
24}
25
26// Enable extracting Arc<EventStore> from AppState
27// This allows handlers that expect State<Arc<EventStore>> to work with AppState
28impl axum::extract::FromRef<AppState> for Arc<EventStore> {
29    fn from_ref(state: &AppState) -> Self {
30        state.store.clone()
31    }
32}
33
34pub async fn serve_v1(
35    store: Arc<EventStore>,
36    auth_manager: Arc<AuthManager>,
37    tenant_manager: Arc<TenantManager>,
38    rate_limiter: Arc<RateLimiter>,
39    addr: &str,
40) -> anyhow::Result<()> {
41    let app_state = AppState {
42        store,
43        auth_manager: auth_manager.clone(),
44        tenant_manager,
45    };
46
47    let auth_state = AuthState {
48        auth_manager: auth_manager.clone(),
49    };
50
51    let rate_limit_state = RateLimitState { rate_limiter };
52
53    let app = Router::new()
54        // Public routes (no auth)
55        .route("/health", get(crate::api::health))
56        .route("/metrics", get(crate::api::prometheus_metrics))
57        // Auth routes
58        .route("/api/v1/auth/register", post(register_handler))
59        .route("/api/v1/auth/login", post(login_handler))
60        .route("/api/v1/auth/me", get(me_handler))
61        .route("/api/v1/auth/api-keys", post(create_api_key_handler))
62        .route("/api/v1/auth/api-keys", get(list_api_keys_handler))
63        .route("/api/v1/auth/api-keys/:id", delete(revoke_api_key_handler))
64        .route("/api/v1/auth/users", get(list_users_handler))
65        .route("/api/v1/auth/users/:id", delete(delete_user_handler))
66        // Tenant routes (protected)
67        .route("/api/v1/tenants", post(create_tenant_handler))
68        .route("/api/v1/tenants", get(list_tenants_handler))
69        .route("/api/v1/tenants/:id", get(get_tenant_handler))
70        .route("/api/v1/tenants/:id/stats", get(get_tenant_stats_handler))
71        .route("/api/v1/tenants/:id/quotas", put(update_quotas_handler))
72        .route(
73            "/api/v1/tenants/:id/deactivate",
74            post(deactivate_tenant_handler),
75        )
76        .route(
77            "/api/v1/tenants/:id/activate",
78            post(activate_tenant_handler),
79        )
80        .route("/api/v1/tenants/:id", delete(delete_tenant_handler))
81        // Event and data routes (protected by auth)
82        .route("/api/v1/events", post(crate::api::ingest_event))
83        .route("/api/v1/events/query", get(crate::api::query_events))
84        .route("/api/v1/events/stream", get(crate::api::events_websocket))
85        .route(
86            "/api/v1/entities/:entity_id/state",
87            get(crate::api::get_entity_state),
88        )
89        .route(
90            "/api/v1/entities/:entity_id/snapshot",
91            get(crate::api::get_entity_snapshot),
92        )
93        .route("/api/v1/stats", get(crate::api::get_stats))
94        // Analytics
95        .route(
96            "/api/v1/analytics/frequency",
97            get(crate::api::analytics_frequency),
98        )
99        .route(
100            "/api/v1/analytics/summary",
101            get(crate::api::analytics_summary),
102        )
103        .route(
104            "/api/v1/analytics/correlation",
105            get(crate::api::analytics_correlation),
106        )
107        // Snapshots
108        .route("/api/v1/snapshots", post(crate::api::create_snapshot))
109        .route("/api/v1/snapshots", get(crate::api::list_snapshots))
110        .route(
111            "/api/v1/snapshots/:entity_id/latest",
112            get(crate::api::get_latest_snapshot),
113        )
114        // Compaction
115        .route(
116            "/api/v1/compaction/trigger",
117            post(crate::api::trigger_compaction),
118        )
119        .route(
120            "/api/v1/compaction/stats",
121            get(crate::api::compaction_stats),
122        )
123        // Schemas
124        .route("/api/v1/schemas", post(crate::api::register_schema))
125        .route("/api/v1/schemas", get(crate::api::list_subjects))
126        .route("/api/v1/schemas/:subject", get(crate::api::get_schema))
127        .route(
128            "/api/v1/schemas/:subject/versions",
129            get(crate::api::list_schema_versions),
130        )
131        .route(
132            "/api/v1/schemas/validate",
133            post(crate::api::validate_event_schema),
134        )
135        .route(
136            "/api/v1/schemas/:subject/compatibility",
137            put(crate::api::set_compatibility_mode),
138        )
139        // Replay
140        .route("/api/v1/replay", post(crate::api::start_replay))
141        .route("/api/v1/replay", get(crate::api::list_replays))
142        .route(
143            "/api/v1/replay/:replay_id",
144            get(crate::api::get_replay_progress),
145        )
146        .route(
147            "/api/v1/replay/:replay_id/cancel",
148            post(crate::api::cancel_replay),
149        )
150        .route(
151            "/api/v1/replay/:replay_id",
152            delete(crate::api::delete_replay),
153        )
154        // Pipelines
155        .route("/api/v1/pipelines", post(crate::api::register_pipeline))
156        .route("/api/v1/pipelines", get(crate::api::list_pipelines))
157        .route(
158            "/api/v1/pipelines/stats",
159            get(crate::api::all_pipeline_stats),
160        )
161        .route(
162            "/api/v1/pipelines/:pipeline_id",
163            get(crate::api::get_pipeline),
164        )
165        .route(
166            "/api/v1/pipelines/:pipeline_id",
167            delete(crate::api::remove_pipeline),
168        )
169        .route(
170            "/api/v1/pipelines/:pipeline_id/stats",
171            get(crate::api::get_pipeline_stats),
172        )
173        .route(
174            "/api/v1/pipelines/:pipeline_id/reset",
175            put(crate::api::reset_pipeline),
176        )
177        .with_state(app_state)
178        .layer(middleware::from_fn_with_state(auth_state, auth_middleware))
179        .layer(middleware::from_fn_with_state(
180            rate_limit_state,
181            rate_limit_middleware,
182        ))
183        .layer(
184            CorsLayer::new()
185                .allow_origin(Any)
186                .allow_methods(Any)
187                .allow_headers(Any),
188        )
189        .layer(TraceLayer::new_for_http());
190
191    let listener = tokio::net::TcpListener::bind(addr).await?;
192    axum::serve(listener, app).await?;
193
194    Ok(())
195}