//! Pinned message management — maps to `message_pin` table. //! //! A channel can have multiple pinned messages with explicit ordering. //! Unlike the `message.pinned` boolean (which just marks the row), //! this table tracks *who* pinned, *when*, and the display *position*. use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; /// One pinned message entry. Ordered by `position` ascending. #[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)] pub struct MessagePin { pub id: Uuid, pub channel_id: Uuid, pub message_id: Uuid, /// Who pinned this message. pub pinned_by: Uuid, /// Display position in the pinned list (0 = top). pub position: i32, pub created_at: DateTime, } /// Summary view returned by list-pins APIs (joined with message content). #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PinDetail { #[serde(flatten)] pub pin: MessagePin, pub message_body: String, pub message_author_id: Uuid, pub message_created_at: DateTime, } #[cfg(test)] mod tests { use super::*; #[test] fn test_pin_detail_serialize() { let pin = MessagePin { id: Uuid::now_v7(), channel_id: Uuid::now_v7(), message_id: Uuid::now_v7(), pinned_by: Uuid::now_v7(), position: 0, created_at: Utc::now(), }; let detail = PinDetail { pin, message_body: "important announcement".to_string(), message_author_id: Uuid::now_v7(), message_created_at: Utc::now(), }; let json = serde_json::to_value(&detail).unwrap(); assert_eq!(json["position"], 0); assert_eq!(json["message_body"], "important announcement"); } }