Skip to main content

velesdb_server/
lib.rs

1// Server — triaged pedantic/nursery lints (Sprint 2 Wave 8, A.10).
2// Blanket `#![allow(clippy::pedantic)]` removed; each remaining lint is
3// justified below.  Axum handler signatures, utoipa derives, and
4// OpenAPI-documented error contracts drive most of these.
5#![allow(clippy::uninlined_format_args)] // readability in error messages
6#![allow(clippy::manual_let_else)] // pattern matching in handlers is clearer
7#![allow(clippy::cast_possible_truncation)] // u128→u64 timing casts are bounded
8#![allow(clippy::cast_sign_loss)] // Duration→u64 timing casts are non-negative
9#![allow(clippy::cast_precision_loss)] // byte-count→f64 display casts are fine
10#![allow(clippy::ref_option)] // utoipa-generated code triggers this
11#![allow(clippy::match_same_arms)] // explicit arms improve readability in routers
12#![allow(clippy::trivially_copy_pass_by_ref)] // Axum extractors require &
13#![allow(clippy::map_unwrap_or)] // readability preference
14#![allow(clippy::enum_glob_use)] // StatusCode::* in handlers
15#![allow(clippy::unused_async)] // Axum requires async signature even for sync handlers
16#![allow(clippy::needless_for_each)] // readability in metric recording loops
17#![allow(clippy::doc_markdown)] // backtick pedantry — docs use utoipa annotations
18#![allow(clippy::missing_errors_doc)] // errors documented in #[utoipa::path] responses
19#![allow(clippy::must_use_candidate)] // handlers return impl IntoResponse, not Option
20#![allow(clippy::similar_names)] // handler params are intentionally close (name/names)
21#![allow(clippy::needless_raw_string_hashes)] // cosmetic, low-value fix
22#![allow(clippy::needless_pass_by_value)] // Axum extractors consume by value
23#![allow(clippy::redundant_closure_for_method_calls)] // readability in map chains
24#![allow(clippy::single_match_else)] // pattern matching in handlers is clearer
25#![allow(clippy::assigning_clones)]
26// minor optimisation, not performance-critical
27// The crate README is pulled into the crate documentation verbatim, so that
28// `cargo test --doc --package velesdb-server` type-checks every ```rust block it
29// contains. Today `README.md` only holds `bash`, `json` and `toml` blocks, which
30// rustdoc never compiles; the include is what makes any future Rust snippet
31// checked by the compiler instead of drifting away from the API unnoticed.
32// Blocks that must not be compiled or executed have to carry an explicit
33// rustdoc attribute in the README (`rust,no_run`, `rust,ignore`).
34#![doc = include_str!("../README.md")]
35//!
36//! ---
37//!
38//! # Crate-level notes
39//!
40//! `VelesDB` Server - REST API library for the `VelesDB` vector database.
41//!
42//! This module provides the HTTP handlers and types for the `VelesDB` REST API.
43//!
44//! ## OpenAPI Documentation
45//!
46//! The API is documented using OpenAPI 3.0. Access the interactive documentation at:
47//! - Swagger UI: `GET /swagger-ui`
48//! - OpenAPI JSON: `GET /api-docs/openapi.json`
49
50pub mod auth;
51pub mod config;
52mod handlers;
53pub mod onboarding;
54pub mod rate_limit;
55pub mod routes;
56mod security_addon;
57pub mod tls;
58mod types;
59
60use security_addon::SecurityAddon;
61use std::sync::atomic::AtomicBool;
62use std::sync::Arc;
63use utoipa::OpenApi;
64use velesdb_core::{
65    Database, DurationHistogram, OperationalMetrics, QueryLimits, TraversalMetrics,
66};
67
68pub use onboarding::OnboardingMetrics;
69pub use types::*;
70
71pub use handlers::{
72    aggregate, analyze_collection, batch_search, bulk_delete_points, collection_diagnostics,
73    collection_sanity, compact_collection, create_collection, create_index, delete_collection,
74    delete_index, delete_point, enable_streaming, explain, flush_collection, get_collection,
75    get_collection_config, get_collection_stats, get_guardrails, get_point, get_point_relations,
76    health_check, hybrid_search, is_empty, list_collections, list_indexes, match_query,
77    multi_query_search, multi_query_search_ids, query, readiness_check, rebuild_index,
78    relate_points, reorder_for_locality, scroll_points, search, search_ids, set_point_ttl,
79    stream_insert, stream_upsert_points, text_search, unrelate_points, update_guardrails,
80    upsert_points, upsert_points_raw, vacuum_collection,
81};
82
83pub use handlers::graph::{
84    add_edge, add_edges_batch, get_edge_count, get_edges, get_node_degree, get_node_edges,
85    get_node_payload, graph_search, list_nodes, remove_edge, stream_traverse, traverse_graph,
86    traverse_parallel, upsert_node_payload, DegreeResponse, EdgeCountResponse, GraphSearchRequest,
87    GraphSearchResponse, NodeEdgeQueryParams, NodeListResponse, NodePayloadResponse,
88    ParallelTraverseRequest, StreamDoneEvent, StreamNodeEvent, StreamStatsEvent,
89    StreamTraverseParams, TraversalResultItem, TraversalStats, TraverseRequest, TraverseResponse,
90    UpsertNodePayloadRequest,
91};
92
93#[cfg(feature = "prometheus")]
94pub use handlers::metrics::{health_metrics, prometheus_metrics};
95
96// ============================================================================
97// OpenAPI Documentation
98
99/// VelesDB API Documentation (paths that exist regardless of build features).
100///
101/// The `/metrics` path lives in [`MetricsApiDoc`] because `utoipa`'s `paths(...)`
102/// list is a fixed macro argument list — individual entries can't carry a
103/// `#[cfg(...)]`, so a handler gated behind the `prometheus` feature can't be
104/// listed here unconditionally without breaking `--no-default-features` builds.
105#[derive(OpenApi)]
106#[openapi(
107    info(
108        title = "VelesDB API",
109        version = env!("CARGO_PKG_VERSION"),
110        description = "High-performance vector database for AI applications. \
111            Supports semantic search, HNSW indexing, and multiple distance metrics. \
112            Authentication is optional — when API keys are configured via VELESDB_API_KEYS, \
113            all endpoints except /health and /ready require a valid Bearer token.",
114        license(name = "VelesDB Core License 1.0", url = "https://github.com/cyberlife-coder/VelesDB/blob/main/LICENSE"),
115        contact(name = "VelesDB Team", url = "https://github.com/cyberlife-coder/VelesDB")
116    ),
117    security(
118        ("bearer_auth" = [])
119    ),
120    modifiers(&SecurityAddon),
121    servers(
122        (url = "/", description = "Local server")
123    ),
124    tags(
125        (name = "health", description = "Health check endpoints"),
126        (name = "collections", description = "Collection management"),
127        (name = "points", description = "Vector point operations"),
128        (name = "search", description = "Vector similarity search"),
129        (name = "query", description = "VelesQL query execution"),
130        (name = "indexes", description = "Property index management (EPIC-009)"),
131        (name = "graph", description = "Graph traversal and edge operations"),
132        (name = "guardrails", description = "Query guard-rails configuration (EPIC-048)"),
133        (name = "metrics", description = "Prometheus operational metrics")
134    ),
135    paths(
136        handlers::health::health_check,
137        handlers::health::readiness_check,
138        handlers::collections::list_collections,
139        handlers::collections::create_collection,
140        handlers::collections::get_collection,
141        handlers::collections::delete_collection,
142        handlers::collections::collection_sanity,
143        handlers::collections::is_empty,
144        handlers::collections::flush_collection,
145        handlers::admin::analyze_collection,
146        handlers::admin::get_collection_stats,
147        handlers::admin::collection_diagnostics,
148        handlers::admin::get_guardrails,
149        handlers::admin::update_guardrails,
150        handlers::points::upsert_points,
151        handlers::points::raw::upsert_points_raw,
152        handlers::points::stream_upsert_points,
153        handlers::points::stream_insert,
154        handlers::points::enable_streaming,
155        handlers::points::get_point,
156        handlers::points::delete_point,
157        handlers::points::scroll_points,
158        handlers::search::search,
159        handlers::search::batch_search,
160        handlers::search::multi_query_search,
161        handlers::search::multi_query_search_ids,
162        handlers::search::text_search,
163        handlers::search::hybrid_search,
164        handlers::search::search_ids,
165        handlers::admin::get_collection_config,
166        handlers::query::query,
167        handlers::query::aggregate,
168        handlers::query::explain,
169        handlers::indexes::create_index,
170        handlers::indexes::list_indexes,
171        handlers::indexes::delete_index,
172        handlers::graph::handlers::get_edges,
173        handlers::graph::handlers::add_edge,
174        handlers::graph::handlers::add_edges_batch,
175        handlers::graph::handlers_extended::remove_edge,
176        handlers::graph::handlers_extended::get_edge_count,
177        handlers::graph::handlers_extended::list_nodes,
178        handlers::graph::handlers_extended::get_node_edges,
179        handlers::graph::handlers_extended::get_node_payload,
180        handlers::graph::handlers_extended::upsert_node_payload,
181        handlers::graph::handlers::traverse_graph,
182        handlers::graph::handlers_extended::traverse_parallel,
183        handlers::graph::handlers::get_node_degree,
184        handlers::graph::handlers_extended::graph_search,
185        handlers::graph::stream::stream_traverse,
186        handlers::match_query::match_query,
187        handlers::admin::rebuild_index,
188        handlers::admin::vacuum_collection,
189        handlers::admin::compact_collection,
190        handlers::admin::reorder_for_locality,
191        handlers::points::bulk_delete_points,
192        handlers::points::relations::relate_points,
193        handlers::points::relations::unrelate_points,
194        handlers::points::relations::get_point_relations,
195        handlers::points::relations::set_point_ttl,
196    ),
197    components(
198        schemas(
199            CreateCollectionRequest,
200            CollectionResponse,
201            UpsertPointsRequest,
202            PointRequest,
203            StreamInsertRequest,
204            EnableStreamingRequest,
205            SearchRequest,
206            BatchSearchRequest,
207            TextSearchRequest,
208            HybridSearchRequest,
209            MultiQuerySearchRequest,
210            SearchResponse,
211            BatchSearchResponse,
212            SearchResultResponse,
213            SearchIdsResponse,
214            IdScoreResult,
215            CollectionConfigResponse,
216            ErrorResponse,
217            QueryRequest,
218            QueryResponse,
219            QueryResponseMeta,
220            AggregationResponse,
221            QueryErrorResponse,
222            QueryErrorDetail,
223            VelesqlErrorResponse,
224            VelesqlErrorDetail,
225            ExplainRequest,
226            ExplainResponse,
227            ExplainStep,
228            ExplainCost,
229            ExplainFeatures,
230            ActualStatsResponse,
231            NodeStatsResponse,
232            CreateIndexRequest,
233            IndexResponse,
234            ListIndexesResponse,
235            CollectionStatsResponse,
236            ColumnStatsResponse,
237            IndexStatsResponse,
238            ScrollRequest,
239            ScrollResponse,
240            ScrollPoint,
241            GuardRailsConfigRequest,
242            GuardRailsConfigResponse,
243            CollectionDiagnosticsResponse,
244            handlers::graph::TraverseRequest,
245            handlers::graph::TraverseResponse,
246            handlers::graph::TraversalResultItem,
247            handlers::graph::TraversalStats,
248            handlers::graph::DegreeResponse,
249            handlers::graph::AddEdgeRequest,
250            handlers::graph::AddEdgesBatchRequest,
251            handlers::graph::AddEdgesBatchResponse,
252            handlers::graph::EdgesResponse,
253            handlers::graph::EdgeResponse,
254            handlers::graph::EdgeCountResponse,
255            handlers::graph::NodeListResponse,
256            handlers::graph::NodePayloadResponse,
257            handlers::graph::UpsertNodePayloadRequest,
258            handlers::graph::ParallelTraverseRequest,
259            handlers::graph::GraphSearchRequest,
260            handlers::graph::GraphSearchResponse,
261            handlers::graph::GraphSearchResultItem,
262            handlers::graph::StreamNodeEvent,
263            handlers::graph::StreamStatsEvent,
264            handlers::graph::StreamDoneEvent,
265            handlers::match_query::MatchQueryRequest,
266            handlers::match_query::MatchQueryResponse,
267            handlers::match_query::MatchQueryResultItem,
268            handlers::match_query::MatchQueryMeta,
269            handlers::points::BulkDeleteRequest,
270            handlers::points::relations::RelateRequest,
271            handlers::points::relations::RelateResponse,
272            handlers::points::relations::RelationEdge,
273            handlers::points::relations::RelationsResponse,
274            handlers::points::relations::SetTtlRequest
275        )
276    )
277)]
278struct ApiDocBase;
279
280/// OpenAPI doc fragment for the `/metrics` endpoint, only compiled when the
281/// `prometheus` feature is enabled (see [`ApiDocBase`] for why this is split out).
282#[cfg(feature = "prometheus")]
283#[derive(OpenApi)]
284#[openapi(paths(handlers::metrics::prometheus_metrics))]
285struct MetricsApiDoc;
286
287/// Public entry point for the full OpenAPI document. Merges in the
288/// `prometheus`-gated `/metrics` path when that feature is enabled.
289pub struct ApiDoc;
290
291impl ApiDoc {
292    pub fn openapi() -> utoipa::openapi::OpenApi {
293        #[allow(unused_mut)]
294        let mut doc = ApiDocBase::openapi();
295        #[cfg(feature = "prometheus")]
296        {
297            doc = doc.merge_from(MetricsApiDoc::openapi());
298        }
299        doc
300    }
301}
302
303// ============================================================================
304// Application State
305
306/// Application state shared across handlers.
307pub struct AppState {
308    /// The `VelesDB` database instance.
309    pub db: Database,
310    /// New-user onboarding diagnostics counters.
311    pub onboarding_metrics: onboarding::OnboardingMetrics,
312    /// Query guard-rails configuration (EPIC-048).
313    pub query_limits: parking_lot::RwLock<QueryLimits>,
314    /// Readiness flag — `true` once the database is fully loaded.
315    pub ready: AtomicBool,
316    /// Operational metrics: query throughput, connections, doc counts (EPIC-050).
317    pub operational_metrics: Arc<OperationalMetrics>,
318    /// Graph traversal metrics: nodes visited, depth, edges scanned.
319    pub traversal_metrics: Arc<TraversalMetrics>,
320    /// Query duration histogram for Prometheus export.
321    pub query_duration_histogram: Arc<DurationHistogram>,
322}
323
324// ============================================================================
325// Tests
326
327#[cfg(test)]
328#[path = "lib_tests.rs"]
329mod tests;