vectorizer_sdk/
models.rs

1//! Data models for the Vectorizer SDK
2
3use std::collections::HashMap;
4
5use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7
8// Re-export hybrid search models
9pub mod hybrid_search;
10pub use hybrid_search::*;
11
12// Re-export graph models
13pub mod graph;
14pub use graph::*;
15
16// Re-export file upload models
17pub mod file_upload;
18pub use file_upload::*;
19
20// ===== CLIENT-SIDE REPLICATION CONFIGURATION =====
21
22/// Read preference for routing read operations.
23/// Similar to MongoDB's read preferences.
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
25#[serde(rename_all = "snake_case")]
26pub enum ReadPreference {
27    /// Route all reads to master
28    Master,
29    /// Route reads to replicas (round-robin)
30    #[default]
31    Replica,
32    /// Route to the node with lowest latency
33    Nearest,
34}
35
36/// Host configuration for master/replica topology.
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct HostConfig {
39    /// Master node URL (receives all write operations)
40    pub master: String,
41    /// Replica node URLs (receive read operations based on read_preference)
42    pub replicas: Vec<String>,
43}
44
45/// Options that can be passed to read operations for per-operation override.
46#[derive(Debug, Clone, Default)]
47pub struct ReadOptions {
48    /// Override the default read preference for this operation
49    pub read_preference: Option<ReadPreference>,
50}
51
52/// Vector similarity metrics
53#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
54#[serde(rename_all = "snake_case")]
55pub enum SimilarityMetric {
56    /// Cosine similarity
57    #[default]
58    Cosine,
59    /// Euclidean distance
60    Euclidean,
61    /// Dot product
62    DotProduct,
63}
64
65/// Vector representation
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct Vector {
68    /// Unique identifier for the vector
69    pub id: String,
70    /// Vector data as an array of numbers
71    pub data: Vec<f32>,
72    /// Optional metadata associated with the vector
73    pub metadata: Option<HashMap<String, serde_json::Value>>,
74    /// Optional ECC public key for payload encryption (PEM, base64, or hex format)
75    #[serde(skip_serializing_if = "Option::is_none")]
76    pub public_key: Option<String>,
77}
78
79/// Collection representation
80#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct Collection {
82    /// Collection name
83    pub name: String,
84    /// Vector dimension
85    pub dimension: usize,
86    /// Similarity metric used for search (API may return as 'metric')
87    #[serde(alias = "similarity_metric")]
88    pub metric: Option<String>,
89    /// Optional description
90    #[serde(default)]
91    pub description: Option<String>,
92    /// Creation timestamp
93    #[serde(default)]
94    pub created_at: Option<String>,
95    /// Last update timestamp
96    #[serde(default)]
97    pub updated_at: Option<String>,
98    /// Vector count
99    #[serde(default)]
100    pub vector_count: usize,
101    /// Document count
102    #[serde(default)]
103    pub document_count: usize,
104    /// Embedding provider
105    #[serde(default)]
106    pub embedding_provider: Option<String>,
107    /// Indexing status
108    #[serde(default)]
109    pub indexing_status: Option<serde_json::Value>,
110    /// Normalization config
111    #[serde(default)]
112    pub normalization: Option<serde_json::Value>,
113    /// Quantization config
114    #[serde(default)]
115    pub quantization: Option<serde_json::Value>,
116    /// Size info
117    #[serde(default)]
118    pub size: Option<serde_json::Value>,
119}
120
121/// Collection information
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct CollectionInfo {
124    /// Collection name
125    pub name: String,
126    /// Vector dimension
127    pub dimension: usize,
128    /// Similarity metric used for search
129    pub metric: String,
130    /// Number of vectors in the collection
131    #[serde(default)]
132    pub vector_count: usize,
133    /// Number of documents in the collection
134    #[serde(default)]
135    pub document_count: usize,
136    /// Creation timestamp
137    pub created_at: String,
138    /// Last update timestamp
139    pub updated_at: String,
140    /// Indexing status
141    #[serde(default)]
142    pub indexing_status: Option<IndexingStatus>,
143}
144
145/// Indexing status
146#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct IndexingStatus {
148    /// Status
149    pub status: String,
150    /// Progress percentage
151    pub progress: f32,
152    /// Total documents
153    pub total_documents: usize,
154    /// Processed documents
155    pub processed_documents: usize,
156    /// Vector count
157    pub vector_count: usize,
158    /// Estimated time remaining
159    pub estimated_time_remaining: Option<String>,
160    /// Last updated timestamp
161    pub last_updated: String,
162}
163
164/// Search result
165#[derive(Debug, Clone, Serialize, Deserialize)]
166pub struct SearchResult {
167    /// Vector ID
168    pub id: String,
169    /// Similarity score
170    pub score: f32,
171    /// Vector content (if available)
172    pub content: Option<String>,
173    /// Optional metadata
174    pub metadata: Option<HashMap<String, serde_json::Value>>,
175}
176
177/// Search response
178#[derive(Debug, Clone, Serialize, Deserialize)]
179pub struct SearchResponse {
180    /// Search results
181    pub results: Vec<SearchResult>,
182    /// Query time in milliseconds
183    pub query_time_ms: f64,
184}
185
186/// Embedding request
187#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct EmbeddingRequest {
189    /// Text to embed
190    pub text: String,
191    /// Optional model to use for embedding
192    pub model: Option<String>,
193    /// Optional parameters for embedding generation
194    pub parameters: Option<EmbeddingParameters>,
195}
196
197/// Embedding parameters
198#[derive(Debug, Clone, Serialize, Deserialize)]
199pub struct EmbeddingParameters {
200    /// Maximum sequence length
201    pub max_length: Option<usize>,
202    /// Whether to normalize the embedding
203    pub normalize: Option<bool>,
204    /// Optional prefix for the text
205    pub prefix: Option<String>,
206}
207
208/// Embedding response
209#[derive(Debug, Clone, Serialize, Deserialize)]
210pub struct EmbeddingResponse {
211    /// Generated embedding vector
212    pub embedding: Vec<f32>,
213    /// Model used for embedding
214    pub model: String,
215    /// Text that was embedded
216    pub text: String,
217    /// Embedding dimension
218    pub dimension: usize,
219    /// Provider used
220    pub provider: String,
221}
222
223/// Health status
224#[derive(Debug, Clone, Serialize, Deserialize)]
225pub struct HealthStatus {
226    /// Service status
227    pub status: String,
228    /// Service version
229    pub version: String,
230    /// Timestamp
231    pub timestamp: String,
232    /// Uptime in seconds
233    pub uptime: Option<u64>,
234    /// Number of collections
235    pub collections: Option<usize>,
236    /// Total number of vectors
237    pub total_vectors: Option<usize>,
238}
239
240/// Collections list response
241#[derive(Debug, Clone, Serialize, Deserialize)]
242pub struct CollectionsResponse {
243    /// List of collections
244    pub collections: Vec<Collection>,
245}
246
247/// Create collection response
248#[derive(Debug, Clone, Serialize, Deserialize)]
249pub struct CreateCollectionResponse {
250    /// Success message
251    pub message: String,
252    /// Collection name
253    pub collection: String,
254}
255
256/// Database statistics
257#[derive(Debug, Clone, Serialize, Deserialize)]
258pub struct DatabaseStats {
259    /// Total number of collections
260    pub total_collections: usize,
261    /// Total number of vectors
262    pub total_vectors: usize,
263    /// Total memory estimate in bytes
264    pub total_memory_estimate_bytes: usize,
265    /// Collections information
266    pub collections: Vec<CollectionStats>,
267}
268
269/// Collection statistics
270#[derive(Debug, Clone, Serialize, Deserialize)]
271pub struct CollectionStats {
272    /// Collection name
273    pub name: String,
274    /// Number of vectors
275    pub vector_count: usize,
276    /// Vector dimension
277    pub dimension: usize,
278    /// Memory estimate in bytes
279    pub memory_estimate_bytes: usize,
280}
281
282/// Batch text request
283#[derive(Debug, Clone, Serialize, Deserialize)]
284pub struct BatchTextRequest {
285    /// Text ID
286    pub id: String,
287    /// Text content
288    pub text: String,
289    /// Optional metadata
290    pub metadata: Option<HashMap<String, String>>,
291}
292
293/// Batch configuration
294#[derive(Debug, Clone, Serialize, Deserialize)]
295pub struct BatchConfig {
296    /// Maximum batch size
297    pub max_batch_size: Option<usize>,
298    /// Number of parallel workers
299    pub parallel_workers: Option<usize>,
300    /// Whether operations should be atomic
301    pub atomic: Option<bool>,
302}
303
304/// Batch insert request
305#[derive(Debug, Clone, Serialize, Deserialize)]
306pub struct BatchInsertRequest {
307    /// Texts to insert
308    pub texts: Vec<BatchTextRequest>,
309    /// Batch configuration
310    pub config: Option<BatchConfig>,
311}
312
313/// Batch response
314#[derive(Debug, Clone, Serialize, Deserialize)]
315pub struct BatchResponse {
316    /// Whether the operation was successful
317    pub success: bool,
318    /// Collection name
319    pub collection: String,
320    /// Operation type
321    pub operation: String,
322    /// Total number of operations
323    pub total_operations: usize,
324    /// Number of successful operations
325    pub successful_operations: usize,
326    /// Number of failed operations
327    pub failed_operations: usize,
328    /// Duration in milliseconds
329    pub duration_ms: u64,
330    /// Error messages
331    pub errors: Vec<String>,
332}
333
334/// Batch search query
335#[derive(Debug, Clone, Serialize, Deserialize)]
336pub struct BatchSearchQuery {
337    /// Query text
338    pub query: String,
339    /// Maximum number of results
340    pub limit: Option<usize>,
341    /// Minimum score threshold
342    pub score_threshold: Option<f32>,
343}
344
345/// Batch search request
346#[derive(Debug, Clone, Serialize, Deserialize)]
347pub struct BatchSearchRequest {
348    /// Search queries
349    pub queries: Vec<BatchSearchQuery>,
350    /// Batch configuration
351    pub config: Option<BatchConfig>,
352}
353
354/// Batch search response
355#[derive(Debug, Clone, Serialize, Deserialize)]
356pub struct BatchSearchResponse {
357    /// Whether the operation was successful
358    pub success: bool,
359    /// Collection name
360    pub collection: String,
361    /// Total number of queries
362    pub total_queries: usize,
363    /// Number of successful queries
364    pub successful_queries: usize,
365    /// Number of failed queries
366    pub failed_queries: usize,
367    /// Duration in milliseconds
368    pub duration_ms: u64,
369    /// Search results
370    pub results: Vec<Vec<SearchResult>>,
371    /// Error messages
372    pub errors: Vec<String>,
373}
374
375/// Batch vector update
376#[derive(Debug, Clone, Serialize, Deserialize)]
377pub struct BatchVectorUpdate {
378    /// Vector ID
379    pub id: String,
380    /// New vector data (optional)
381    pub data: Option<Vec<f32>>,
382    /// New metadata (optional)
383    pub metadata: Option<HashMap<String, serde_json::Value>>,
384}
385
386/// Batch update request
387#[derive(Debug, Clone, Serialize, Deserialize)]
388pub struct BatchUpdateRequest {
389    /// Vector updates
390    pub updates: Vec<BatchVectorUpdate>,
391    /// Batch configuration
392    pub config: Option<BatchConfig>,
393}
394
395/// Batch delete request
396#[derive(Debug, Clone, Serialize, Deserialize)]
397pub struct BatchDeleteRequest {
398    /// Vector IDs to delete
399    pub vector_ids: Vec<String>,
400    /// Batch configuration
401    pub config: Option<BatchConfig>,
402}
403
404/// Summarization methods
405#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
406#[serde(rename_all = "snake_case")]
407pub enum SummarizationMethod {
408    /// Extractive summarization
409    #[default]
410    Extractive,
411    /// Keyword summarization
412    Keyword,
413    /// Sentence summarization
414    Sentence,
415    /// Abstractive summarization
416    Abstractive,
417}
418
419/// Summarize text request
420#[derive(Debug, Clone, Serialize, Deserialize)]
421pub struct SummarizeTextRequest {
422    /// Text to summarize
423    pub text: String,
424    /// Summarization method
425    pub method: Option<SummarizationMethod>,
426    /// Maximum summary length
427    pub max_length: Option<usize>,
428    /// Compression ratio
429    pub compression_ratio: Option<f32>,
430    /// Language code
431    pub language: Option<String>,
432}
433
434/// Summarize text response
435#[derive(Debug, Clone, Serialize, Deserialize)]
436pub struct SummarizeTextResponse {
437    /// Summary ID
438    pub summary_id: String,
439    /// Original text
440    pub original_text: String,
441    /// Generated summary
442    pub summary: String,
443    /// Method used
444    pub method: String,
445    /// Original text length
446    pub original_length: usize,
447    /// Summary length
448    pub summary_length: usize,
449    /// Compression ratio
450    pub compression_ratio: f32,
451    /// Language
452    pub language: String,
453    /// Status
454    pub status: String,
455    /// Message
456    pub message: String,
457    /// Metadata
458    pub metadata: HashMap<String, String>,
459}
460
461/// Summarize context request
462#[derive(Debug, Clone, Serialize, Deserialize)]
463pub struct SummarizeContextRequest {
464    /// Context to summarize
465    pub context: String,
466    /// Summarization method
467    pub method: Option<SummarizationMethod>,
468    /// Maximum summary length
469    pub max_length: Option<usize>,
470    /// Compression ratio
471    pub compression_ratio: Option<f32>,
472    /// Language code
473    pub language: Option<String>,
474}
475
476/// Summarize context response
477#[derive(Debug, Clone, Serialize, Deserialize)]
478pub struct SummarizeContextResponse {
479    /// Summary ID
480    pub summary_id: String,
481    /// Original context
482    pub original_context: String,
483    /// Generated summary
484    pub summary: String,
485    /// Method used
486    pub method: String,
487    /// Original context length
488    pub original_length: usize,
489    /// Summary length
490    pub summary_length: usize,
491    /// Compression ratio
492    pub compression_ratio: f32,
493    /// Language
494    pub language: String,
495    /// Status
496    pub status: String,
497    /// Message
498    pub message: String,
499    /// Metadata
500    pub metadata: HashMap<String, String>,
501}
502
503/// Get summary response
504#[derive(Debug, Clone, Serialize, Deserialize)]
505pub struct GetSummaryResponse {
506    /// Summary ID
507    pub summary_id: String,
508    /// Original text
509    pub original_text: String,
510    /// Generated summary
511    pub summary: String,
512    /// Method used
513    pub method: String,
514    /// Original text length
515    pub original_length: usize,
516    /// Summary length
517    pub summary_length: usize,
518    /// Compression ratio
519    pub compression_ratio: f32,
520    /// Language
521    pub language: String,
522    /// Creation timestamp
523    pub created_at: String,
524    /// Metadata
525    pub metadata: HashMap<String, String>,
526    /// Status
527    pub status: String,
528}
529
530/// Summary info
531#[derive(Debug, Clone, Serialize, Deserialize)]
532pub struct SummaryInfo {
533    /// Summary ID
534    pub summary_id: String,
535    /// Method used
536    pub method: String,
537    /// Language
538    pub language: String,
539    /// Original text length
540    pub original_length: usize,
541    /// Summary length
542    pub summary_length: usize,
543    /// Compression ratio
544    pub compression_ratio: f32,
545    /// Creation timestamp
546    pub created_at: String,
547    /// Metadata
548    pub metadata: HashMap<String, String>,
549}
550
551/// List summaries response
552#[derive(Debug, Clone, Serialize, Deserialize)]
553pub struct ListSummariesResponse {
554    /// List of summaries
555    pub summaries: Vec<SummaryInfo>,
556    /// Total count
557    pub total_count: usize,
558    /// Status
559    pub status: String,
560}
561
562/// Indexing progress
563#[derive(Debug, Clone, Serialize, Deserialize)]
564pub struct IndexingProgress {
565    /// Whether indexing is in progress
566    pub is_indexing: bool,
567    /// Overall status
568    pub overall_status: String,
569    /// Collections being indexed
570    pub collections: Vec<CollectionProgress>,
571}
572
573/// Collection progress
574#[derive(Debug, Clone, Serialize, Deserialize)]
575pub struct CollectionProgress {
576    /// Collection name
577    pub collection_name: String,
578    /// Status
579    pub status: String,
580    /// Progress percentage
581    pub progress: f32,
582    /// Vector count
583    pub vector_count: usize,
584    /// Error message if any
585    pub error_message: Option<String>,
586    /// Last updated timestamp
587    pub last_updated: String,
588}
589
590// ===== INTELLIGENT SEARCH MODELS =====
591
592/// Intelligent search request
593#[derive(Debug, Clone, Serialize, Deserialize)]
594pub struct IntelligentSearchRequest {
595    /// Search query
596    pub query: String,
597    /// Collections to search (optional - searches all if not specified)
598    pub collections: Option<Vec<String>>,
599    /// Maximum number of results
600    pub max_results: Option<usize>,
601    /// Enable domain expansion
602    pub domain_expansion: Option<bool>,
603    /// Enable technical focus
604    pub technical_focus: Option<bool>,
605    /// Enable MMR diversification
606    pub mmr_enabled: Option<bool>,
607    /// MMR balance parameter (0.0-1.0)
608    pub mmr_lambda: Option<f32>,
609}
610
611/// Semantic search request
612#[derive(Debug, Clone, Serialize, Deserialize)]
613pub struct SemanticSearchRequest {
614    /// Search query
615    pub query: String,
616    /// Collection to search
617    pub collection: String,
618    /// Maximum number of results
619    pub max_results: Option<usize>,
620    /// Enable semantic reranking
621    pub semantic_reranking: Option<bool>,
622    /// Enable cross-encoder reranking
623    pub cross_encoder_reranking: Option<bool>,
624    /// Minimum similarity threshold
625    pub similarity_threshold: Option<f32>,
626}
627
628/// Contextual search request
629#[derive(Debug, Clone, Serialize, Deserialize)]
630pub struct ContextualSearchRequest {
631    /// Search query
632    pub query: String,
633    /// Collection to search
634    pub collection: String,
635    /// Metadata-based context filters
636    pub context_filters: Option<HashMap<String, serde_json::Value>>,
637    /// Maximum number of results
638    pub max_results: Option<usize>,
639    /// Enable context-aware reranking
640    pub context_reranking: Option<bool>,
641    /// Weight of context factors (0.0-1.0)
642    pub context_weight: Option<f32>,
643}
644
645/// Multi-collection search request
646#[derive(Debug, Clone, Serialize, Deserialize)]
647pub struct MultiCollectionSearchRequest {
648    /// Search query
649    pub query: String,
650    /// Collections to search
651    pub collections: Vec<String>,
652    /// Maximum results per collection
653    pub max_per_collection: Option<usize>,
654    /// Maximum total results
655    pub max_total_results: Option<usize>,
656    /// Enable cross-collection reranking
657    pub cross_collection_reranking: Option<bool>,
658}
659
660/// Intelligent search result
661#[derive(Debug, Clone, Serialize, Deserialize)]
662pub struct IntelligentSearchResult {
663    /// Result ID
664    pub id: String,
665    /// Similarity score
666    pub score: f32,
667    /// Result content
668    pub content: String,
669    /// Metadata
670    pub metadata: Option<HashMap<String, serde_json::Value>>,
671    /// Collection name
672    pub collection: Option<String>,
673    /// Query used for this result
674    pub query_used: Option<String>,
675}
676
677/// Intelligent search response
678#[derive(Debug, Clone, Serialize, Deserialize)]
679pub struct IntelligentSearchResponse {
680    /// Search results
681    pub results: Vec<IntelligentSearchResult>,
682    /// Total number of results found
683    pub total_results: usize,
684    /// Search duration in milliseconds
685    pub duration_ms: u64,
686    /// Queries generated
687    pub queries_generated: Option<Vec<String>>,
688    /// Collections searched
689    pub collections_searched: Option<Vec<String>>,
690    /// Search metadata
691    pub metadata: Option<HashMap<String, serde_json::Value>>,
692}
693
694/// Semantic search response
695#[derive(Debug, Clone, Serialize, Deserialize)]
696pub struct SemanticSearchResponse {
697    /// Search results
698    pub results: Vec<IntelligentSearchResult>,
699    /// Total number of results found
700    pub total_results: usize,
701    /// Search duration in milliseconds
702    pub duration_ms: u64,
703    /// Collection searched
704    pub collection: String,
705    /// Search metadata
706    pub metadata: Option<HashMap<String, serde_json::Value>>,
707}
708
709/// Contextual search response
710#[derive(Debug, Clone, Serialize, Deserialize)]
711pub struct ContextualSearchResponse {
712    /// Search results
713    pub results: Vec<IntelligentSearchResult>,
714    /// Total number of results found
715    pub total_results: usize,
716    /// Search duration in milliseconds
717    pub duration_ms: u64,
718    /// Collection searched
719    pub collection: String,
720    /// Context filters applied
721    pub context_filters: Option<HashMap<String, serde_json::Value>>,
722    /// Search metadata
723    pub metadata: Option<HashMap<String, serde_json::Value>>,
724}
725
726/// Multi-collection search response
727#[derive(Debug, Clone, Serialize, Deserialize)]
728pub struct MultiCollectionSearchResponse {
729    /// Search results
730    pub results: Vec<IntelligentSearchResult>,
731    /// Total number of results found
732    pub total_results: usize,
733    /// Search duration in milliseconds
734    pub duration_ms: u64,
735    /// Collections searched
736    pub collections_searched: Vec<String>,
737    /// Results per collection
738    pub results_per_collection: Option<HashMap<String, usize>>,
739    /// Search metadata
740    pub metadata: Option<HashMap<String, serde_json::Value>>,
741}
742
743// ==================== REPLICATION MODELS ====================
744
745/// Status of a replica node
746#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
747#[serde(rename_all = "PascalCase")]
748pub enum ReplicaStatus {
749    /// Replica is connected and healthy
750    Connected,
751    /// Replica is syncing data
752    Syncing,
753    /// Replica is lagging behind master
754    Lagging,
755    /// Replica is disconnected
756    Disconnected,
757}
758
759/// Information about a replica node
760#[derive(Debug, Clone, Serialize, Deserialize)]
761pub struct ReplicaInfo {
762    /// Unique identifier for the replica
763    pub replica_id: String,
764    /// Hostname or IP address of the replica
765    pub host: String,
766    /// Port number of the replica
767    pub port: u16,
768    /// Current status of the replica
769    pub status: String,
770    /// Timestamp of last heartbeat
771    pub last_heartbeat: DateTime<Utc>,
772    /// Number of operations successfully synced
773    pub operations_synced: u64,
774
775    // Legacy fields (backwards compatible)
776    /// Legacy: Current offset on replica (deprecated, use operations_synced)
777    #[serde(skip_serializing_if = "Option::is_none")]
778    pub offset: Option<u64>,
779    /// Legacy: Lag in operations (deprecated, use status)
780    #[serde(skip_serializing_if = "Option::is_none")]
781    pub lag: Option<u64>,
782}
783
784/// Statistics for replication status
785#[derive(Debug, Clone, Serialize, Deserialize)]
786pub struct ReplicationStats {
787    // New fields (v1.2.0+)
788    /// Role of the node: Master or Replica
789    #[serde(skip_serializing_if = "Option::is_none")]
790    pub role: Option<String>,
791    /// Total bytes sent to replicas (Master only)
792    #[serde(skip_serializing_if = "Option::is_none")]
793    pub bytes_sent: Option<u64>,
794    /// Total bytes received from master (Replica only)
795    #[serde(skip_serializing_if = "Option::is_none")]
796    pub bytes_received: Option<u64>,
797    /// Timestamp of last synchronization
798    #[serde(skip_serializing_if = "Option::is_none")]
799    pub last_sync: Option<DateTime<Utc>>,
800    /// Number of operations pending replication
801    #[serde(skip_serializing_if = "Option::is_none")]
802    pub operations_pending: Option<usize>,
803    /// Size of snapshot data in bytes
804    #[serde(skip_serializing_if = "Option::is_none")]
805    pub snapshot_size: Option<usize>,
806    /// Number of connected replicas (Master only)
807    #[serde(skip_serializing_if = "Option::is_none")]
808    pub connected_replicas: Option<usize>,
809
810    // Legacy fields (backwards compatible - always present)
811    /// Current offset on master node
812    pub master_offset: u64,
813    /// Current offset on replica node
814    pub replica_offset: u64,
815    /// Number of operations behind
816    pub lag_operations: u64,
817    /// Total operations replicated
818    pub total_replicated: u64,
819}
820
821/// Response for replication status endpoint
822#[derive(Debug, Clone, Serialize, Deserialize)]
823pub struct ReplicationStatusResponse {
824    /// Overall status message
825    pub status: String,
826    /// Detailed replication statistics
827    pub stats: ReplicationStats,
828    /// Optional message with additional information
829    #[serde(skip_serializing_if = "Option::is_none")]
830    pub message: Option<String>,
831}
832
833/// Response for listing replicas
834#[derive(Debug, Clone, Serialize, Deserialize)]
835pub struct ReplicaListResponse {
836    /// List of replica nodes
837    pub replicas: Vec<ReplicaInfo>,
838    /// Total count of replicas
839    pub count: usize,
840    /// Status message
841    pub message: String,
842}