diff --git a/Cargo.toml b/Cargo.toml
index 8f73be0..dc28830 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,21 +1,3 @@
-[package]
-name = "meowlog"
-version = "0.1.0"
-edition = "2021"
-
-[dependencies]
-bincode = "1.3.3"
-chrono = { version = "0.4.38", features = ["serde"] }
-clap = { version = "4.5.20", features = ["derive"] }
-color-eyre = "0.6.3"
-inquire = "0.7.5"
-lazy_static = "1.5.0"
-serde = { version = "1.0.210", features = ["derive"] }
-serde_json = "1.0.128"
-strum = { version = "0.26.3", features = ["derive"] }
-strum_macros = "0.26.4"
-toml = "0.8.19"
-uuid = { version = "1.10.0", features = ["serde", "v4"] }
-
-[build-dependencies]
-clap_complete = "4.5.33"
+[workspace]
+resolver = "2"
+members = ["client", "server"]
diff --git a/README.md b/README.md
index 2141ff2..8feb2b9 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,35 @@
+![img.png](assets/img.png)
+
 # meowlog
 ---
-## WIP NOT WORKING AND SUBJECT TO CHANGE
+
+## WIP SUBJECT TO CHANGE
+
+### ⚠️ IMPORTANT
+
+The client's core functionality (managing substances and ingestions) works. The codebase is a mess and will be heavily
+refactired so use at your own risk. There will be no backwards compatibility until the first stable release.
+
+Planned features:
+
+- [x] Managing ingestions and substances
+- [ ] Having a sensible set of default substances (taken from tripsit or psychonautwiki idk yet)
+- [ ] Circular Concurrency Checking for binary files
+- [ ] Server with syncing capabilities and maybe also a frontend with a similar featureset like the Psychonaut Wiki
+  Journal app
+- [ ] Referring to harm reduction resources in the CLI
+
+Current problems:
+
+- [ ] Codebase is a mess
+- [ ] No tests
+- [ ] Poor error handling
+- [ ] Unoptimized memory usage
+
 ---
+
+### Client usage:
+
 ```
 Commands:
   add-ingestion     Adds ingestion
diff --git a/assets/img.png b/assets/img.png
new file mode 100644
index 0000000..5a379d5
Binary files /dev/null and b/assets/img.png differ
diff --git a/Cargo.lock b/client/Cargo.lock
similarity index 93%
rename from Cargo.lock
rename to client/Cargo.lock
index 4d28f98..1a6b205 100644
--- a/Cargo.lock
+++ b/client/Cargo.lock
@@ -17,6 +17,37 @@ version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
+[[package]]
+name = "aes"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561"
+dependencies = [
+ "aes-soft",
+ "aesni",
+ "cipher",
+]
+
+[[package]]
+name = "aes-soft"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072"
+dependencies = [
+ "cipher",
+ "opaque-debug",
+]
+
+[[package]]
+name = "aesni"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce"
+dependencies = [
+ "cipher",
+ "opaque-debug",
+]
+
 [[package]]
 name = "android-tzdata"
 version = "0.1.1"
@@ -165,6 +196,15 @@ dependencies = [
  "windows-targets 0.52.6",
 ]
 
+[[package]]
+name = "cipher"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801"
+dependencies = [
+ "generic-array",
+]
+
 [[package]]
 name = "clap"
 version = "4.5.20"
@@ -253,6 +293,21 @@ version = "0.8.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 
+[[package]]
+name = "crc"
+version = "3.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636"
+dependencies = [
+ "crc-catalog",
+]
+
+[[package]]
+name = "crc-catalog"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
+
 [[package]]
 name = "crossterm"
 version = "0.25.0"
@@ -318,6 +373,16 @@ dependencies = [
  "byteorder",
 ]
 
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
 [[package]]
 name = "getrandom"
 version = "0.2.15"
@@ -462,11 +527,13 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
 name = "meowlog"
 version = "0.1.0"
 dependencies = [
+ "aes",
  "bincode",
  "chrono",
  "clap",
  "clap_complete",
  "color-eyre",
+ "crc",
  "inquire",
  "lazy_static",
  "serde",
@@ -531,6 +598,12 @@ version = "1.20.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
 
+[[package]]
+name = "opaque-debug"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
+
 [[package]]
 name = "owo-colors"
 version = "3.5.0"
@@ -833,6 +906,12 @@ dependencies = [
  "tracing-core",
 ]
 
+[[package]]
+name = "typenum"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+
 [[package]]
 name = "unicode-ident"
 version = "1.0.13"
@@ -873,6 +952,12 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
 
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
 [[package]]
 name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
diff --git a/client/Cargo.toml b/client/Cargo.toml
new file mode 100644
index 0000000..fd8dbdf
--- /dev/null
+++ b/client/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "meowlog"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+bincode = "1.3.3"
+aes = "0.6.0"
+crc = "3.2.1"
+chrono = { version = "0.4.38", features = ["serde"] }
+clap = { version = "4.5.20", features = ["derive"] }
+color-eyre = "0.6.3"
+inquire = "0.7.5"
+lazy_static = "1.5.0"
+serde = { version = "1.0.210", features = ["derive"] }
+serde_json = "1.0.128"
+strum = { version = "0.26.3", features = ["derive"] }
+strum_macros = "0.26.4"
+toml = "0.8.19"
+uuid = { version = "1.10.0", features = ["serde", "v4"] }
+
+[build-dependencies]
+clap_complete = "4.5.33"
diff --git a/src/config.rs b/client/src/config.rs
similarity index 100%
rename from src/config.rs
rename to client/src/config.rs
diff --git a/src/ingestions.rs b/client/src/ingestions.rs
similarity index 89%
rename from src/ingestions.rs
rename to client/src/ingestions.rs
index d5371a0..b381e3c 100644
--- a/src/ingestions.rs
+++ b/client/src/ingestions.rs
@@ -25,7 +25,15 @@ pub struct Ingestion {
 
 impl std::fmt::Display for Ingestion {
     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        write!(f, "{} {}   {} {}{}", self.date, self.time.format("%H:%M"), self.substance.name, self.dose.value, self.dose.unit)
+        write!(
+            f,
+            "{} {}   {} {}{}",
+            self.date,
+            self.time.format("%H:%M"),
+            self.substance.name,
+            self.dose.value,
+            self.dose.unit
+        )
     }
 }
 
@@ -113,7 +121,6 @@ pub fn list_ingestions() -> Result<(), std::io::Error> {
     Ok(())
 }
 
-
 pub fn edit_ingestion() -> Result<(), std::io::Error> {
     let ing_des = ensure_ingestion_files();
     if ing_des.is_empty() {
@@ -124,17 +131,36 @@ pub fn edit_ingestion() -> Result<(), std::io::Error> {
     let mut ingest_sel_vec_id: Vec<Uuid> = Vec::new();
     let mut ingest_sel_vec_ing: Vec<Ingestion> = Vec::new();
 
-
     for ingestion in ing_des.clone().into_iter() {
         ingest_sel_vec_id.push(ingestion.0);
         ingest_sel_vec_ing.push(ingestion.1);
     }
 
-    let ingest_select = inquire::Select::new("Which ingestion do you want to edit?", ingest_sel_vec_ing).prompt().unwrap();
-    let ing_id = ing_des.iter()
-        .map(|(key, &ref val)| if val.substance.name == ingest_select.substance.name && val.substance.substance_class == ingest_select.substance.substance_class && val.date == ingest_select.date && val.time == ingest_select.time { key.clone() } else { unreachable!() }).collect::<Vec<Uuid>>();
+    let ingest_select =
+        inquire::Select::new("Which ingestion do you want to edit?", ingest_sel_vec_ing)
+            .prompt()
+            .unwrap();
+    let ing_id = ing_des
+        .iter()
+        .map(|(key, &ref val)| {
+            if val.substance.name == ingest_select.substance.name
+                && val.substance.substance_class == ingest_select.substance.substance_class
+                && val.date == ingest_select.date
+                && val.time == ingest_select.time
+            {
+                key.clone()
+            } else {
+                unreachable!()
+            }
+        })
+        .collect::<Vec<Uuid>>();
 
-    let edit_select = inquire::MultiSelect::new("What do you want to edit?", vec!["Substance", "Dose", "Ingestion Method", "Time", "Date"]).prompt().unwrap();
+    let edit_select = inquire::MultiSelect::new(
+        "What do you want to edit?",
+        vec!["Substance", "Dose", "Ingestion Method", "Time", "Date"],
+    )
+    .prompt()
+    .unwrap();
 
     for edit in edit_select {
         match edit {
@@ -249,3 +275,4 @@ pub fn create_ingestions_file() -> Result<(), std::io::Error> {
     let hash_ser = bincode::serialize(&hash).unwrap();
     std::fs::write(INGESTIONS_FILE.to_string(), hash_ser)
 }
+
diff --git a/src/ingestions_util.rs b/client/src/ingestions_util.rs
similarity index 68%
rename from src/ingestions_util.rs
rename to client/src/ingestions_util.rs
index 4e5aa4e..1d89e6d 100644
--- a/src/ingestions_util.rs
+++ b/client/src/ingestions_util.rs
@@ -11,7 +11,8 @@ use uuid::Uuid;
 pub fn ensure_ingestion_files() -> HashMap<Uuid, Ingestion> {
     let ingesstions_bytes_loaded_des: HashMap<Uuid, Ingestion>;
     if path_exists(INGESTIONS_FILE.to_string()) {
-        let substances_bytes_loaded = std::fs::read(INGESTIONS_FILE.to_string()).expect("Could not read ingestions file");
+        let substances_bytes_loaded =
+            std::fs::read(INGESTIONS_FILE.to_string()).expect("Could not read ingestions file");
         ingesstions_bytes_loaded_des = bincode::deserialize(&substances_bytes_loaded).expect("Could not deserialize ingestions file. If you are tech-savvy try fixing it with a hex editor.");
     } else {
         std::fs::File::create(INGESTIONS_FILE.to_string()).unwrap();
@@ -24,37 +25,32 @@ pub fn ensure_ingestion_files() -> HashMap<Uuid, Ingestion> {
 }
 
 pub fn get_user_date(current: NaiveDateTime) -> chrono::NaiveDate {
-    let current_time = current.time();
     let current_date = current.date();
-    let date: chrono::NaiveDate = inquire::CustomType::<chrono::NaiveDate>::new(
-        "Enter the date (YYYY-MM-DD):",
-    )
-        .with_placeholder("YYYY-MM-DD")
-        .with_default(current_date)
-        .with_parser(&|input| {
-            chrono::NaiveDate::parse_from_str(input, "%Y-%m-%d").map_err(|_| ())
-        })
-        .with_error_message("Please enter a valid date and time in the format YYYY-MM-DD")
-        .with_help_message("Use the format YYYY-MM-DD")
-        .prompt()
-        .unwrap();
+    let date: chrono::NaiveDate =
+        inquire::CustomType::<chrono::NaiveDate>::new("Enter the date (YYYY-MM-DD):")
+            .with_placeholder("YYYY-MM-DD")
+            .with_default(current_date)
+            .with_parser(&|input| {
+                chrono::NaiveDate::parse_from_str(input, "%Y-%m-%d").map_err(|_| ())
+            })
+            .with_error_message("Please enter a valid date and time in the format YYYY-MM-DD")
+            .with_help_message("Use the format YYYY-MM-DD")
+            .prompt()
+            .unwrap();
     date
 }
 
 pub fn get_user_time(current: NaiveDateTime) -> chrono::NaiveTime {
     let current_time = current.time();
-    let time: chrono::NaiveTime = inquire::CustomType::<chrono::NaiveTime>::new(
-        "Enter the time (HH:MM):",
-    )
-        .with_placeholder("HH:MM")
-        .with_default(current_time)
-        .with_parser(&|input| {
-            chrono::NaiveTime::parse_from_str(input, "%H:%M").map_err(|_| ())
-        })
-        .with_error_message("Please enter a valid time in the format HH:MM.")
-        .with_help_message("Use the format HH:MM")
-        .prompt()
-        .unwrap();
+    let time: chrono::NaiveTime =
+        inquire::CustomType::<chrono::NaiveTime>::new("Enter the time (HH:MM):")
+            .with_placeholder("HH:MM")
+            .with_default(current_time)
+            .with_parser(&|input| chrono::NaiveTime::parse_from_str(input, "%H:%M").map_err(|_| ()))
+            .with_error_message("Please enter a valid time in the format HH:MM.")
+            .with_help_message("Use the format HH:MM")
+            .prompt()
+            .unwrap();
     time
 }
 
@@ -63,8 +59,8 @@ pub fn get_dose_unit() -> DoseUnit {
         "What unit should be used?",
         DoseUnit::iter().collect::<Vec<_>>(),
     )
-        .prompt()
-        .unwrap();
+    .prompt()
+    .unwrap();
     dose_unit
 }
 
@@ -81,7 +77,13 @@ pub fn get_substance() -> Substance {
     let substance_file: HashMap<Uuid, Substance> = crate::substance_util::ensure_substance_file();
     let substances: Vec<Substance> = substance_file
         .into_iter()
-        .filter_map(|(_, s)| if s.name == substance_select { Some(s) } else { None })
+        .filter_map(|(_, s)| {
+            if s.name == substance_select {
+                Some(s)
+            } else {
+                None
+            }
+        })
         .collect();
 
     if substances.len() != 1 {
@@ -100,8 +102,8 @@ pub fn get_ingestion_method() -> IngestionMethod {
         "How did you ingest?",
         IngestionMethod::iter().collect::<Vec<_>>(),
     )
-        .prompt()
-        .unwrap();
+    .prompt()
+    .unwrap();
     ingestion_method
 }
 
diff --git a/src/main.rs b/client/src/main.rs
similarity index 97%
rename from src/main.rs
rename to client/src/main.rs
index 388a12a..534ce72 100644
--- a/src/main.rs
+++ b/client/src/main.rs
@@ -55,7 +55,7 @@ fn main() {
 
     match &cli.command {
         Some(Commands::AddIngestion) => ingestions::add_ingestion(),
-        Some(Commands::EditIngestion) => {ingestions::edit_ingestion().unwrap()}
+        Some(Commands::EditIngestion) => ingestions::edit_ingestion().unwrap(),
         Some(Commands::ListIngestions) => ingestions::list_ingestions().unwrap(),
         Some(Commands::RemoveIngestion) => {}
         Some(Commands::AddSubstance) => substances::add_substance().unwrap(),
diff --git a/src/substance_util.rs b/client/src/substance_util.rs
similarity index 100%
rename from src/substance_util.rs
rename to client/src/substance_util.rs
diff --git a/src/substances.rs b/client/src/substances.rs
similarity index 100%
rename from src/substances.rs
rename to client/src/substances.rs
diff --git a/src/util.rs b/client/src/util.rs
similarity index 100%
rename from src/util.rs
rename to client/src/util.rs
diff --git a/meowlog.proto b/meowlog.proto
new file mode 100644
index 0000000..385c5b6
--- /dev/null
+++ b/meowlog.proto
@@ -0,0 +1,30 @@
+syntax = "proto3";
+package meowlog;
+
+service MeowlogSync {
+  rpc GetLogs(GetLogsRequest) returns (GetLogsResponse) {}
+  rpc AddLog(AddLogRequest) returns (AddLogResponse) {}
+}
+
+message GetLogsRequest {
+  string query = 1;
+}
+
+message GetLogsResponse {
+  repeated Log logs = 1;
+}
+
+message AddLogRequest {
+  Log log = 1;
+}
+
+message AddLogResponse {
+  bool success = 1;
+}
+
+message Log {
+  string id = 1;
+  string message = 2;
+  string level = 3;
+  string timestamp = 4;
+}
\ No newline at end of file