diff --git a/amadeus/src/components/config/mod.rs b/amadeus/src/components/config/mod.rs
index 331b2114a0dfa464a181882c71cf08b397a098d0..9b21e81bf7a707436d64ee06e3b3876e0227a649 100644
--- a/amadeus/src/components/config/mod.rs
+++ b/amadeus/src/components/config/mod.rs
@@ -22,7 +22,7 @@ use lektor_utils::{
     logger,
 };
 use serde::{Deserialize, Serialize};
-use std::{net::SocketAddr, ops::Deref, sync::Arc};
+use std::{borrow::Cow, net::SocketAddr, ops::Deref, sync::Arc};
 
 pub struct State {
     config: Arc<AmadeusConfig>,
@@ -473,7 +473,16 @@ impl State {
             ]],
             match &self.remote_infos {
                 Some(Some(infos)) => section![ "Remote Infos" => [
-                    text(format!("Server version   {}", infos.version)).size(SIZE_FONT_NORMAL),
+                    row![
+                        text("Server version").size(SIZE_FONT_NORMAL),
+                        horizontal_space(Length::Fill),
+                        text(&infos.version).size(SIZE_FONT_NORMAL),
+                    ],
+                    row![
+                        text("Database epoch").size(SIZE_FONT_NORMAL),
+                        horizontal_space(Length::Fill),
+                        text(infos.last_epoch.map(|x| x.to_string().into()).unwrap_or(Cow::Borrowed("None"))).size(SIZE_FONT_NORMAL),
+                    ],
                 ]],
                 _ => None,
             },
diff --git a/lektor_lib/src/requests.rs b/lektor_lib/src/requests.rs
index e7c65408bec9dc3feca0e6dc7ea01f8cc6c719ec..f49ff34867e5212f01263ace5180e5d8a03e507d 100644
--- a/lektor_lib/src/requests.rs
+++ b/lektor_lib/src/requests.rs
@@ -279,7 +279,8 @@ pub async fn search_karas(
     from: SearchFrom,
     by: KaraBy,
 ) -> Result<Vec<KId>> {
-    let (len, obj) = encode_base64_value(SearchData { from, regex: by })?;
+    let regex = vec![by];
+    let (len, obj) = encode_base64_value(SearchData { from, regex })?;
     let get = std::str::from_utf8(&obj[..len])?;
     Ok(request!(config; GET @ "/search/{get}" => Vec<KId>))
 }
@@ -289,7 +290,8 @@ pub async fn count_karas(
     from: SearchFrom,
     by: KaraBy,
 ) -> Result<usize> {
-    let (len, obj) = encode_base64_value(SearchData { from, regex: by })?;
+    let regex = vec![by];
+    let (len, obj) = encode_base64_value(SearchData { from, regex })?;
     let get = std::str::from_utf8(&obj[..len])?;
     Ok(request!(config; GET @ "/count/{get}" => usize))
 }
diff --git a/lektor_nkdb/src/database/epoch.rs b/lektor_nkdb/src/database/epoch.rs
index dc9044f23da8148a9e1d70197dd19144457ec058..c09db611feea06b8f69d05d273a3cc88ea580b34 100644
--- a/lektor_nkdb/src/database/epoch.rs
+++ b/lektor_nkdb/src/database/epoch.rs
@@ -6,14 +6,14 @@ use crate::*;
 /// The epoch contains all available karas at a certain point in time. It can be submitted and
 /// available to all readers of the database or unsubmited and only one writter can edit it.
 #[derive(Debug, Default)]
-pub(crate) struct Epoch(EpochData);
+pub(crate) struct Epoch(EpochData, u64);
 
 /// Represent the data contained in an epoch.
 pub type EpochData = HashMap<KId, Kara>;
 
-impl From<EpochData> for Epoch {
-    fn from(value: EpochData) -> Self {
-        Self(value)
+impl From<(EpochData, u64)> for Epoch {
+    fn from((data, num): (EpochData, u64)) -> Self {
+        Self(data, num)
     }
 }
 
@@ -54,4 +54,9 @@ impl Epoch {
     pub fn data_mut(&mut self) -> &mut EpochData {
         &mut self.0
     }
+
+    /// Get the number of the epoch
+    pub fn epoch_num(&self) -> u64 {
+        self.1
+    }
 }
diff --git a/lektor_nkdb/src/lib.rs b/lektor_nkdb/src/lib.rs
index 7ad89a4e7340f0791f1cd66605473db60ca5e644..3e3aec6495cdb61eba2b8b71c46fc0cd0d8f0a51 100644
--- a/lektor_nkdb/src/lib.rs
+++ b/lektor_nkdb/src/lib.rs
@@ -142,8 +142,15 @@ impl<Storage: DatabaseStorage> Database<Storage> {
     }
 
     /// Search the database with a specific regex.
-    pub async fn search(&self, from: SearchFrom, regex: KaraBy) -> Result<Vec<KId>> {
-        let regex = Search::new(regex)?;
+    pub async fn search(&self, from: SearchFrom, regex: Vec<KaraBy>) -> Result<Vec<KId>> {
+        let (regex, error): (Vec<_>, Vec<_>) = regex
+            .into_iter()
+            .map(SearchBy::new)
+            .partition(Result::is_ok);
+        if let Some(Err(err)) = error.into_iter().next() {
+            bail!("failed to search karas: {err}");
+        }
+        let regex = SearchBy::from_iter(regex.into_iter().map(Result::unwrap));
         let kids = match from {
             SearchFrom::Playlist(plt) => self.playlists.get_content(plt).await.unwrap_or_default(),
             SearchFrom::History => self.history(RangeFull).await,
@@ -180,7 +187,7 @@ impl<Storage: DatabaseStorage> Database<Storage> {
     }
 
     /// Returns the kara count from the search set.
-    pub async fn count(&self, from: SearchFrom, regex: KaraBy) -> usize {
+    pub async fn count(&self, from: SearchFrom, regex: Vec<KaraBy>) -> usize {
         log::error!("find a way to not allocate the search result buffer...");
         self.search(from, regex)
             .await
@@ -193,6 +200,11 @@ impl<Storage: DatabaseStorage> Database<Storage> {
         self.epochs.last().await
     }
 
+    /// Get the last epoch from the database.
+    pub async fn last_epoch_num(&self) -> Option<u64> {
+        self.epochs.last().await.map(|epoch| epoch.epoch_num())
+    }
+
     /// Get the current kara with the play state.
     ///
     /// We have to do shenanigans. Because between karas we have an idle peridod and the playback
diff --git a/lektor_nkdb/src/search/mod.rs b/lektor_nkdb/src/search/mod.rs
index cce5b95d2f676ec8e7aeee6630fa391609c2193a..d93ecd576c0ea0b18ca61d767b188e76ef5114e1 100644
--- a/lektor_nkdb/src/search/mod.rs
+++ b/lektor_nkdb/src/search/mod.rs
@@ -6,14 +6,11 @@ mod kara_by;
 pub use kara_by::*;
 
 use crate::{playlist::PlaylistName, Kara};
+use anyhow::Result;
 use kurisu_api::v2::{SongOrigin, SongType};
 use regex::Regex;
 use serde::{Deserialize, Serialize};
 
-/// Structure wrapping a regex to fuzzy search into the database or queue for matching karas.
-#[derive(Debug)]
-pub(crate) struct Search(SearchBy);
-
 /// Structure to tell from which KId set we are searching.
 #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
 pub enum SearchFrom {
@@ -44,6 +41,10 @@ impl FromIterator<SearchBy> for SearchBy {
 }
 
 impl SearchBy {
+    pub(crate) fn new(regex: KaraBy) -> Result<Self> {
+        regex.try_into()
+    }
+
     /// Get the list of playlist that are needed for the kara to match. This is the only
     /// informations that is not present in the epoch and thus need to be handled differently...
     pub(crate) fn into_needed_playlists(self) -> Vec<String> {
@@ -80,22 +81,3 @@ impl SearchBy {
         }
     }
 }
-
-impl Search {
-    /// Create a new search regex. We only accept alphanumeric stuff to avoid vulnerabilities
-    /// around regex from untrusted sources. We will do the fuzzy stuff latter.
-    pub(crate) fn new(regex: KaraBy) -> anyhow::Result<Self> {
-        Ok(Self(SearchBy::try_from(regex)?))
-    }
-
-    /// Get the list of playlist that are needed for the kara to match. This is the only
-    /// informations that is not present in the epoch and thus need to be handled differently...
-    pub(crate) fn into_needed_playlists(self) -> Vec<String> {
-        self.0.into_needed_playlists()
-    }
-
-    /// A match function.
-    pub(crate) fn matches(&self, kara: &Kara) -> bool {
-        self.0.matches(kara)
-    }
-}
diff --git a/lektor_nkdb/src/storage/disk_storage.rs b/lektor_nkdb/src/storage/disk_storage.rs
index 6dc408fda4db841bfd123ef6f68c8957984c67cd..4de66f2b63ec686e3a6e40f8dc1fa3fc87c55fe4 100644
--- a/lektor_nkdb/src/storage/disk_storage.rs
+++ b/lektor_nkdb/src/storage/disk_storage.rs
@@ -319,7 +319,7 @@ impl DatabaseStorage for DatabaseDiskStorage {
         })
     }
 
-    async fn read_last_epoch(&self) -> Result<Option<EpochData>> {
+    async fn read_last_epoch(&self) -> Result<Option<(EpochData, u64)>> {
         read_json_folder! {
             (self) "epoch" [get_regex_epoch_ok(), get_regex_epoch_json()] => u64;
             valid_epochs => { match valid_epochs.into_iter().max() {
@@ -342,7 +342,7 @@ impl DatabaseStorage for DatabaseDiskStorage {
                         data.remove(&kid);
                     });
                     log::info!("load epoch {id} with {} karas from path: {}", data.len(), path.to_string_lossy());
-                    Ok(Some(data))
+                    Ok(Some((data, *id)))
                 }
             }}
         }
diff --git a/lektor_nkdb/src/storage/mod.rs b/lektor_nkdb/src/storage/mod.rs
index 974ba4cc27012bfb56aed419e4833e9c59626be4..e43480929b375eef8dcfbba98c61ae73603f5244 100644
--- a/lektor_nkdb/src/storage/mod.rs
+++ b/lektor_nkdb/src/storage/mod.rs
@@ -34,7 +34,7 @@ pub trait DatabaseStorage: Sized + std::fmt::Debug {
     // =========== //
 
     /// Read the last valid epoch from disk/memory/network/like-the-implementation-does.
-    async fn read_last_epoch(&self) -> Result<Option<EpochData>>;
+    async fn read_last_epoch(&self) -> Result<Option<(EpochData, u64)>>;
 
     /// Write the data from an epoch to the disk.
     async fn write_epoch(&self, epoch: &EpochData) -> Result<()>;
diff --git a/lektor_nkdb/src/storage/test_storage.rs b/lektor_nkdb/src/storage/test_storage.rs
index e75c5b3e2fc1632e43b4b021428181609221fbe6..49b418476a9e92abf2d3d8d96aac749e1e263683 100644
--- a/lektor_nkdb/src/storage/test_storage.rs
+++ b/lektor_nkdb/src/storage/test_storage.rs
@@ -23,8 +23,8 @@ impl DatabaseStorage for DatabaseTestStorage {
         Ok(Self(Default::default()))
     }
 
-    async fn read_last_epoch(&self) -> Result<Option<EpochData>> {
-        Ok(Some(self.0.read().await.clone()))
+    async fn read_last_epoch(&self) -> Result<Option<(EpochData, u64)>> {
+        Ok(Some((self.0.read().await.clone(), 1)))
     }
 
     async fn write_epoch(&self, data: &EpochData) -> Result<()> {
diff --git a/lektor_payloads/src/lib.rs b/lektor_payloads/src/lib.rs
index b05cd01711f8345747200e4330173fed79e8a74e..33964b83010894d07ebc217605f4ec5db2b33545 100644
--- a/lektor_payloads/src/lib.rs
+++ b/lektor_payloads/src/lib.rs
@@ -3,26 +3,22 @@
 
 mod playlist_name;
 mod range;
+mod search;
 mod userid;
 
-pub use crate::{playlist_name::*, range::*, userid::LektorUser};
-use anyhow::{anyhow, bail};
+pub use crate::{playlist_name::*, range::*, search::*, userid::LektorUser};
 pub use lektor_nkdb::{
     KId, Kara, KaraBy, KaraStatus, KaraTimeStamps, PlayState, Playlist, PlaylistInfo, Priority,
     RemoteKId, SearchFrom, SongOrigin, SongType, PRIORITY_LENGTH, PRIORITY_VALUES,
 };
 
+use anyhow::{anyhow, bail};
 use serde::{Deserialize, Serialize};
 
 #[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
 pub struct Infos {
     pub version: String,
-}
-
-#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
-pub struct SearchData {
-    pub from: SearchFrom,
-    pub regex: KaraBy,
+    pub last_epoch: Option<u64>,
 }
 
 #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
@@ -59,20 +55,6 @@ pub struct AddArguments {
     pub query: KaraBy,
 }
 
-/// Add to something (playlist/queue/...), or remove something. Some times we can decide to shuffle
-/// the set of kara/the playlist before adding it. For the removing the shuffle flag is ignored.
-#[derive(Debug, Serialize, Deserialize)]
-pub enum KaraFilter {
-    /// A single kara.
-    KId(KId),
-
-    /// A set of karas.
-    List(bool, Vec<KId>),
-
-    /// The content of a playlist.
-    Playlist(bool, PlaylistName),
-}
-
 /// Add to the queue. We add at a certain priority, some times we can decide to shuffle the set of
 /// kara/the playlist before adding it to the queue.
 #[derive(Debug, Serialize, Deserialize)]
@@ -123,39 +105,3 @@ impl std::str::FromStr for AddArguments {
         })
     }
 }
-
-#[cfg(test)]
-mod test {
-    use super::*;
-    use anyhow::Result;
-    use lektor_utils::assert_ok;
-    use serde::{Deserialize, Serialize};
-    use serde_json::json;
-
-    /// Test the json serialization/deserialization to check if we obtains the same object back.
-    fn assert_serde<T: Serialize + for<'de> Deserialize<'de> + std::fmt::Debug + std::cmp::Eq>(
-        obj: T,
-    ) -> Result<()> {
-        let res = serde_json::from_str(&serde_json::to_string(&obj)?)?;
-        assert_eq!(obj, res);
-        Ok(())
-    }
-
-    #[test]
-    fn json_search_data() -> Result<()> {
-        assert_serde(SearchData {
-            from: SearchFrom::Database,
-            regex: KaraBy::Id(42),
-        })?;
-        assert_serde(SearchData {
-            from: SearchFrom::Playlist("jibun".parse().unwrap()),
-            regex: KaraBy::Query("Chicka".to_string()),
-        })?;
-
-        assert_ok!(serde_json::from_value::<SearchData>(json!(
-            {"from":"Database","regex":{"Query":"chicka"}}
-        )));
-
-        Ok(())
-    }
-}
diff --git a/lektor_payloads/src/search.rs b/lektor_payloads/src/search.rs
new file mode 100644
index 0000000000000000000000000000000000000000..bc4567b564e74ad3abf86a0d882e657409b8043a
--- /dev/null
+++ b/lektor_payloads/src/search.rs
@@ -0,0 +1,60 @@
+use crate::*;
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
+pub struct SearchData {
+    pub from: SearchFrom,
+    pub regex: Vec<KaraBy>,
+}
+
+/// Add to something (playlist/queue/...), or remove something. Some times we can decide to shuffle
+/// the set of kara/the playlist before adding it. For the removing the shuffle flag is ignored.
+#[derive(Debug, Serialize, Deserialize)]
+pub enum KaraFilter {
+    /// A single kara.
+    KId(KId),
+
+    /// A set of karas.
+    List(bool, Vec<KId>),
+
+    /// The content of a playlist.
+    Playlist(bool, PlaylistName),
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use anyhow::Result;
+    use lektor_utils::assert_ok;
+    use serde::{Deserialize, Serialize};
+    use serde_json::json;
+
+    /// Test the json serialization/deserialization to check if we obtains the same object back.
+    fn assert_serde<T: Serialize + for<'de> Deserialize<'de> + std::fmt::Debug + std::cmp::Eq>(
+        obj: T,
+    ) -> Result<()> {
+        let res = serde_json::from_str(&serde_json::to_string(&obj)?)?;
+        assert_eq!(obj, res);
+        Ok(())
+    }
+
+    #[test]
+    fn json_search_data() -> Result<()> {
+        assert_serde(SearchData {
+            from: SearchFrom::Database,
+            regex: vec![KaraBy::Id(42)],
+        })?;
+        assert_serde(SearchData {
+            from: SearchFrom::Playlist("jibun".parse().unwrap()),
+            regex: vec![KaraBy::Query("Chicka".to_string())],
+        })?;
+
+        assert_ok!(serde_json::from_value::<SearchData>(json!(
+            { "from":  "Database"
+            , "regex": [ {"Query":"chicka"} ]
+            }
+        )));
+
+        Ok(())
+    }
+}
diff --git a/lektord/src/routes.rs b/lektord/src/routes.rs
index b128ce81ea3b1fe1cab4b09de3d0b8de1a086a82..fca68aefac73fc7db22f9a0a5a627d0728efe29d 100644
--- a/lektord/src/routes.rs
+++ b/lektord/src/routes.rs
@@ -20,9 +20,10 @@ use std::{ops::RangeBounds, str::FromStr};
 use tokio::task::LocalSet;
 
 /// Get informations abount the lektord server.
-pub(crate) async fn root() -> Json<Infos> {
+pub(crate) async fn root(State(state): State<LektorStatePtr>) -> Json<Infos> {
     Json(Infos {
         version: lektor_utils::version().to_string(),
+        last_epoch: state.database.last_epoch_num().await,
     })
 }
 
diff --git a/lkt/src/main.rs b/lkt/src/main.rs
index 55c519fb0de68e00372a87abfbdf5b65410e12eb..1742cf7469341a71f138457ebb1cfe66d8b49c39 100644
--- a/lkt/src/main.rs
+++ b/lkt/src/main.rs
@@ -4,8 +4,6 @@ mod args;
 mod config;
 mod manpage;
 
-use std::ops::RangeBounds;
-
 use crate::{args::*, config::*};
 use anyhow::{anyhow, Result};
 use chrono::TimeZone;
@@ -13,6 +11,7 @@ use futures::{stream, StreamExt};
 use lektor_lib::*;
 use lektor_payloads::*;
 use lektor_utils::*;
+use std::{borrow::Cow, ops::RangeBounds};
 
 fn main() -> Result<()> {
     logger::init(Some(log::Level::Trace)).expect("failed to install logger");
@@ -91,7 +90,10 @@ async fn exec_lkt(config: LktConfig, cmd: SubCommand) -> Result<()> {
 
         // Display the status of lektord
         Playback { status: true, .. } => {
-            let Infos { version } = requests::get_infos(config.clone()).await?;
+            let Infos {
+                version,
+                last_epoch,
+            } = requests::get_infos(config.clone()).await?;
             let PlayStateWithCurrent { state, current } =
                 requests::get_status(config.clone()).await?;
             let current = match current {
@@ -104,6 +106,10 @@ async fn exec_lkt(config: LktConfig, cmd: SubCommand) -> Result<()> {
             };
             let queue_counts = requests::get_queue_count(config.clone()).await?;
             let history_count = requests::get_history_count(config).await?;
+            let last_epoch = match last_epoch {
+                Some(num) => num.to_string().into(),
+                None => Cow::Borrowed("None"),
+            };
 
             println!("Version:          {version}");
             println!("Playback State:   {state:?}");
@@ -114,6 +120,7 @@ async fn exec_lkt(config: LktConfig, cmd: SubCommand) -> Result<()> {
             }
             println!("Karas in Queue:   {queue_counts:?}");
             println!("Karas in Hustory: {history_count}");
+            println!("Database epoch:   {last_epoch}");
 
             Ok(())
         }