diff --git a/.github/workflows/lint_and_test.yml b/.github/workflows/lint_and_test.yml
index 781c44f..700be2f 100644
--- a/.github/workflows/lint_and_test.yml
+++ b/.github/workflows/lint_and_test.yml
@@ -26,4 +26,6 @@ jobs:
         run: cargo clippy --all-targets --all-features -- -D warnings
 
       - name: Run tests
+        env:
+          RUST_MIN_STACK: 8388608
         run: cargo test --verbose
diff --git a/Cargo.toml b/Cargo.toml
index 48740b9..6aaee9c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,17 +4,16 @@ version = "0.1.0"
 edition = "2021"
 
 [dependencies]
-async-stream = "0.3.5"
-futures-core = "0.3.30"
-futures-util = "0.3.30"
-iroh = "0.17.0"
-tokio = { version = "1", features = ["full"] }
-tokio-stream = "0.1.15"
-veilid-core = "0.3.3"
+iroh-blobs = "0.23.0"
+veilid-core = { git = "https://gitlab.com/veilid/veilid.git", version = "0.3.4" }
 eyre = "0.6"
 tracing = "0.1"
 xdg = "2.4"
 tmpdir = "1"
 serde = "1.0.204"
 serde_cbor = "0.11.2"
-clap = "4.5.9"
\ No newline at end of file
+clap = "4.5.9"
+anyhow = "1.0.86"
+tokio = {version ="1.39.3", features=["full"] }
+async-stream = "0.3.5"
+futures-core = "0.3.30"
diff --git a/src/backend.rs b/src/backend.rs
index 3746725..668fb5c 100644
--- a/src/backend.rs
+++ b/src/backend.rs
@@ -1,18 +1,28 @@
-use std::path::{Path, PathBuf};
+use crate::common::{CommonKeypair, DHTEntity};
+use crate::group::Group;
+use crate::repo::Repo;
+use anyhow::{anyhow, Result};
+use iroh_blobs::Hash;
 use std::collections::HashMap;
-use eyre::{Result, anyhow};
+use std::mem;
+use std::path::{Path, PathBuf};
+use std::sync::Arc;
 use tokio::fs;
+use tokio::sync::{mpsc, oneshot};
 use tracing::info;
+use veilid_core::{
+    api_startup_config, vld0_generate_keypair, CryptoKey, CryptoSystem, CryptoSystemVLD0,
+    CryptoTyped, DHTSchema, KeyPair, ProtectedStore, RoutingContext, SharedSecret, UpdateCallback,
+    VeilidAPI, VeilidConfigInner, VeilidUpdate, CRYPTO_KIND_VLD0, TypedKey
+};
 use xdg::BaseDirectories;
-use veilid_core::{VeilidAPI, CryptoKey, VeilidUpdate, VeilidConfigInner, api_startup_config, DHTSchema, CRYPTO_KIND_VLD0, vld0_generate_keypair, CryptoTyped, CryptoSystemVLD0, RoutingContext, KeyPair, ProtectedStore}; // Added ProtectedStore here
-use std::sync::Arc;
-use crate::group::{Group, GroupKeypair};
 
 pub struct Backend {
     path: PathBuf,
     port: u16,
     veilid_api: Option<VeilidAPI>,
     groups: HashMap<CryptoKey, Box<Group>>,
+    repos: HashMap<CryptoKey, Box<Repo>>,
 }
 
 impl Backend {
@@ -22,16 +32,41 @@ impl Backend {
             port,
             veilid_api: None,
             groups: HashMap::new(),
+            repos: HashMap::new(),
         })
     }
 
     pub async fn start(&mut self) -> Result<()> {
-        println!("Starting on {} with port {}", self.path.display(), self.port);
+        println!(
+            "Starting on {} with port {}",
+            self.path.display(),
+            self.port
+        );
         let base_dir = &self.path;
-        fs::create_dir_all(base_dir).await.map_err(|e| anyhow!("Failed to create base directory {}: {}", base_dir.display(), e))?;
+        fs::create_dir_all(base_dir).await.map_err(|e| {
+            anyhow!(
+                "Failed to create base directory {}: {}",
+                base_dir.display(),
+                e
+            )
+        })?;
 
-        let update_callback: Arc<dyn Fn(VeilidUpdate) + Send + Sync> = Arc::new(|update| {
-            info!("Received update: {:?}", update);
+        let (tx, mut rx) = mpsc::channel(1);
+
+        let update_callback: UpdateCallback = Arc::new(move |update| {
+            // Else handle update for something
+            // info!("Received update: {:?}", update);
+            if let VeilidUpdate::Attachment(attachment_state) = &update {
+                if attachment_state.public_internet_ready {
+                    println!("Public internet ready!");
+                    let tx = tx.clone();
+                    tokio::spawn(async move {
+                        if tx.send(()).await.is_err() {
+                            println!("receiver dropped");
+                        }
+                    });
+                }
+            }
         });
 
         let xdg_dirs = BaseDirectories::with_prefix("save-dweb-backend")?;
@@ -44,7 +79,10 @@ impl Backend {
             protected_store: veilid_core::VeilidConfigProtectedStore {
                 allow_insecure_fallback: true,
                 always_use_insecure_storage: true,
-                directory: base_dir.join("protected_store").to_string_lossy().to_string(),
+                directory: base_dir
+                    .join("protected_store")
+                    .to_string_lossy()
+                    .to_string(),
                 delete: false,
                 device_encryption_key_password: "".to_string(),
                 new_device_encryption_key_password: None,
@@ -60,75 +98,113 @@ impl Backend {
             network: Default::default(),
         };
 
-        self.veilid_api = Some(api_startup_config(update_callback, config_inner).await.map_err(|e| anyhow!("Failed to initialize Veilid API: {}", e))?);
+        if self.veilid_api.is_none() {
+            let veilid_api = api_startup_config(update_callback, config_inner)
+                .await
+                .map_err(|e| anyhow!("Failed to initialize Veilid API: {}", e))?;
+            self.veilid_api = Some(veilid_api);
+        } else {
+            return Err(anyhow!("Veilid already initialized"));
+        }
+
+        self.veilid_api.clone().unwrap().attach().await?;
+
+        println!("Waiting for network ready state");
+
+        rx.recv().await.expect("Unable to wait for veilid init");
 
         Ok(())
     }
 
-    pub async fn stop(&self) -> Result<()> {
+    pub async fn stop(&mut self) -> Result<()> {
         println!("Stopping Backend...");
-        if let Some(veilid) = &self.veilid_api {
-            veilid.clone().shutdown().await;
+        if self.veilid_api.is_some() {
+            println!("Shutting down Veilid API");
+            let veilid = self.veilid_api.take();
+            veilid.unwrap().shutdown().await;
+            println!("Veilid API shut down successfully");
+            self.groups = HashMap::new();
+            self.repos = HashMap::new();
         }
         Ok(())
     }
 
     pub async fn create_group(&mut self) -> Result<Group> {
-        let veilid = self.veilid_api.as_ref().ok_or_else(|| anyhow!("Veilid API is not initialized"))?;
+        let veilid = self
+            .veilid_api
+            .as_ref()
+            .ok_or_else(|| anyhow!("Veilid API is not initialized"))?;
         let routing_context = veilid.routing_context()?;
         let schema = DHTSchema::dflt(1)?;
         let kind = Some(CRYPTO_KIND_VLD0);
-
+    
         let dht_record = routing_context.create_dht_record(schema, kind).await?;
         let keypair = vld0_generate_keypair();
-        let encryption_key = CryptoTyped::new(CRYPTO_KIND_VLD0, CryptoKey::new([0; 32]));
-
         let crypto_system = CryptoSystemVLD0::new(veilid.crypto()?);
-
+    
+        let encryption_key = crypto_system.random_shared_secret();
+    
         let group = Group::new(
-            keypair.key.clone(),
-            dht_record,
+            dht_record.clone(),
             encryption_key,
-            Some(CryptoTyped::new(CRYPTO_KIND_VLD0, keypair.secret)),
             Arc::new(routing_context),
             crypto_system,
         );
-
+    
         let protected_store = veilid.protected_store().unwrap();
-        group.store_keypair(&protected_store).await?;
-
-        self.groups.insert(group.get_id(), Box::new(group.clone()));
-
+        CommonKeypair {
+            id: group.id(), 
+            public_key: dht_record.owner().clone(),  
+            secret_key: group.get_secret_key(),
+            encryption_key: group.get_encryption_key(),
+        }
+        .store_keypair(&protected_store)
+        .await
+        .map_err(|e| anyhow!(e))?;
+    
+        self.groups.insert(group.id(), Box::new(group.clone()));
+    
         Ok(group)
     }
 
-    pub async fn get_group(&self, key: CryptoKey) -> Result<Box<Group>> {
-        if let Some(group) = self.groups.get(&key) {
+    pub async fn get_group(&mut self, record_key: TypedKey) -> Result<Box<Group>> {
+        if let Some(group) = self.groups.get(&record_key.value) {
             return Ok(group.clone());
         }
-
-        let protected_store = self.veilid_api.as_ref().unwrap().protected_store().unwrap();
-        let keypair_data = protected_store.load_user_secret(key.to_string()).await.map_err(|_| anyhow!("Failed to load keypair"))?.ok_or_else(|| anyhow!("Keypair not found"))?;
-        let retrieved_keypair: GroupKeypair = serde_cbor::from_slice(&keypair_data).map_err(|_| anyhow!("Failed to deserialize keypair"))?;
-
+    
         let routing_context = self.veilid_api.as_ref().unwrap().routing_context()?;
-        let dht_record = if let Some(secret_key) = retrieved_keypair.secret_key.clone() {
-            routing_context.open_dht_record(CryptoTyped::new(CRYPTO_KIND_VLD0, retrieved_keypair.public_key.clone()), Some(KeyPair { key: retrieved_keypair.public_key.clone(), secret: secret_key })).await?
-        } else {
-            routing_context.open_dht_record(CryptoTyped::new(CRYPTO_KIND_VLD0, retrieved_keypair.public_key.clone()), None).await?
-        };
+        let protected_store = self.veilid_api.as_ref().unwrap().protected_store().unwrap();
+    
+        // Load the keypair associated with the record_key from the protected store
+        let retrieved_keypair = CommonKeypair::load_keypair(&protected_store, &record_key.value)
+            .await
+            .map_err(|_| anyhow!("Failed to load keypair"))?;
 
         let crypto_system = CryptoSystemVLD0::new(self.veilid_api.as_ref().unwrap().crypto()?);
-
-        let group = Group::new(
-            retrieved_keypair.public_key.clone(),
-            dht_record,
-            CryptoTyped::new(CRYPTO_KIND_VLD0, retrieved_keypair.encryption_key),
-            retrieved_keypair.secret_key.map(|sk| CryptoTyped::new(CRYPTO_KIND_VLD0, sk)),
-            Arc::new(routing_context),
+    
+        // First open the DHT record
+        let dht_record = routing_context
+            .open_dht_record(record_key.clone(), None) // Don't pass a writer here yet
+            .await?;
+        
+        // Use the owner key from the DHT record as the default writer
+        let owner_key = dht_record.owner(); // Call the owner() method to get the owner key
+    
+        // Reopen the DHT record with the owner key as the writer
+        let dht_record = routing_context
+            .open_dht_record(record_key.clone(), Some(KeyPair::new(owner_key.clone(), retrieved_keypair.secret_key.clone().unwrap())))
+            .await?;
+    
+    
+        let group = Group {
+            dht_record: dht_record.clone(),
+            encryption_key: retrieved_keypair.encryption_key.clone(),
+            routing_context: Arc::new(routing_context),
             crypto_system,
-        );
-
+            repos: Vec::new(),
+        };
+        self.groups.insert(group.id(), Box::new(group.clone()));
+    
         Ok(Box::new(group))
     }
 
@@ -138,7 +214,7 @@ impl Backend {
 
     pub async fn close_group(&mut self, key: CryptoKey) -> Result<()> {
         if let Some(group) = self.groups.remove(&key) {
-            group.close().await?;
+            group.close().await.map_err(|e| anyhow!(e))?;
         } else {
             return Err(anyhow!("Group not found"));
         }
@@ -151,4 +227,82 @@ impl Backend {
             .ok_or_else(|| anyhow!("Veilid API not initialized"))
             .map(|api| Arc::new(api.protected_store().unwrap()))
     }
+
+    pub async fn create_repo(&mut self) -> Result<Repo> {
+        let veilid = self
+            .veilid_api
+            .as_ref()
+            .ok_or_else(|| anyhow!("Veilid API is not initialized"))?;
+        let routing_context = veilid.routing_context()?;
+        let schema = DHTSchema::dflt(1)?;
+        let kind = Some(CRYPTO_KIND_VLD0);
+
+        let dht_record = routing_context.create_dht_record(schema, kind).await?;
+        let keypair = vld0_generate_keypair();
+        let crypto_system = CryptoSystemVLD0::new(veilid.crypto()?);
+        let encryption_key = crypto_system.random_shared_secret();
+
+        let repo = Repo::new(
+            keypair.key.clone(),
+            dht_record,
+            encryption_key,
+            Some(CryptoTyped::new(CRYPTO_KIND_VLD0, keypair.secret)),
+            Arc::new(routing_context),
+            crypto_system,
+        );
+
+        self.repos.insert(repo.get_id(), Box::new(repo.clone()));
+
+        Ok(repo)
+    }
+
+    pub async fn get_repo(&self, key: CryptoKey) -> Result<Box<Repo>> {
+        if let Some(repo) = self.repos.get(&key) {
+            return Ok(repo.clone());
+        }
+
+        let protected_store = self.veilid_api.as_ref().unwrap().protected_store().unwrap();
+        let keypair_data = protected_store
+            .load_user_secret(key.to_string())
+            .await
+            .map_err(|_| anyhow!("Failed to load keypair"))?
+            .ok_or_else(|| anyhow!("Keypair not found"))?;
+        let retrieved_keypair: CommonKeypair = serde_cbor::from_slice(&keypair_data)
+            .map_err(|_| anyhow!("Failed to deserialize keypair"))?;
+
+        let routing_context = self.veilid_api.as_ref().unwrap().routing_context()?;
+        let dht_record = if let Some(secret_key) = retrieved_keypair.secret_key.clone() {
+            routing_context
+                .open_dht_record(
+                    CryptoTyped::new(CRYPTO_KIND_VLD0, retrieved_keypair.public_key.clone()),
+                    Some(KeyPair {
+                        key: retrieved_keypair.public_key.clone(),
+                        secret: secret_key,
+                    }),
+                )
+                .await?
+        } else {
+            routing_context
+                .open_dht_record(
+                    CryptoTyped::new(CRYPTO_KIND_VLD0, retrieved_keypair.public_key.clone()),
+                    None,
+                )
+                .await?
+        };
+
+        let crypto_system = CryptoSystemVLD0::new(self.veilid_api.as_ref().unwrap().crypto()?);
+
+        let repo = Repo {
+            id: retrieved_keypair.public_key.clone(),
+            dht_record,
+            encryption_key: SharedSecret::new([0; 32]),
+            secret_key: retrieved_keypair
+                .secret_key
+                .map(|sk| CryptoTyped::new(CRYPTO_KIND_VLD0, sk)),
+            routing_context: Arc::new(routing_context),
+            crypto_system,
+        };
+
+        Ok(Box::new(repo))
+    }
 }
diff --git a/src/common.rs b/src/common.rs
new file mode 100644
index 0000000..1d5823e
--- /dev/null
+++ b/src/common.rs
@@ -0,0 +1,109 @@
+#![allow(async_fn_in_trait)]
+#![allow(clippy::async_yields_async)]
+
+use serde::{Serialize, Deserialize};
+use eyre::{Result, anyhow};
+use std::sync::Arc;
+use veilid_core::{
+    CryptoKey, SharedSecret, CryptoTyped, DHTRecordDescriptor, RoutingContext, CryptoSystemVLD0,
+    ProtectedStore, Nonce, CRYPTO_KIND_VLD0, CryptoSystem
+};
+
+#[derive(Serialize, Deserialize)]
+pub struct CommonKeypair {
+    pub id: CryptoKey,
+    pub public_key: CryptoKey,
+    pub secret_key: Option<CryptoKey>,
+    pub encryption_key: SharedSecret,
+}
+
+impl CommonKeypair {
+    pub async fn store_keypair(&self, protected_store: &ProtectedStore) -> Result<()> {
+        let keypair_data = serde_cbor::to_vec(&self).map_err(|e| anyhow!("Failed to serialize keypair: {}", e))?;
+        protected_store.save_user_secret(self.id.to_string(), &keypair_data).await.map_err(|e| anyhow!("Unable to store keypair: {}", e))?;
+        Ok(())
+    }
+
+    pub async fn load_keypair(protected_store: &ProtectedStore, id: &CryptoKey) -> Result<Self> {
+        let keypair_data = protected_store.load_user_secret(id.to_string()).await.map_err(|_| anyhow!("Failed to load keypair"))?.ok_or_else(|| anyhow!("Keypair not found"))?;
+        let retrieved_keypair: CommonKeypair = serde_cbor::from_slice(&keypair_data).map_err(|_| anyhow!("Failed to deserialize keypair"))?;
+        Ok(retrieved_keypair)
+    }
+}
+
+
+pub trait DHTEntity {
+    fn get_id(&self) -> CryptoKey;
+    fn get_encryption_key(&self) -> SharedSecret;
+    fn get_routing_context(&self) -> Arc<RoutingContext>;
+    fn get_crypto_system(&self) -> CryptoSystemVLD0;
+    fn get_dht_record(&self) -> DHTRecordDescriptor;
+    fn get_secret_key(&self) -> Option<CryptoKey>;
+
+    fn encrypt_aead(&self, data: &[u8], associated_data: Option<&[u8]>) -> Result<Vec<u8>> {
+        let nonce = self.get_crypto_system().random_nonce();
+        let mut buffer = Vec::with_capacity(nonce.as_slice().len() + data.len());
+        buffer.extend_from_slice(nonce.as_slice());
+        buffer.extend_from_slice(
+            &self
+                .get_crypto_system()
+                .encrypt_aead(data, &nonce, &self.get_encryption_key(), associated_data)
+                .map_err(|e| anyhow!("Failed to encrypt data: {}", e))?,
+        );
+        Ok(buffer)
+    }
+
+    fn decrypt_aead(&self, data: &[u8], associated_data: Option<&[u8]>) -> Result<Vec<u8>> {
+        let nonce: [u8; 24] = data[..24].try_into().map_err(|_| anyhow!("Failed to convert nonce slice to array"))?;
+        let nonce = Nonce::new(nonce);
+        let encrypted_data = &data[24..];
+        self.get_crypto_system()
+            .decrypt_aead(encrypted_data, &nonce, &self.get_encryption_key(), associated_data)
+            .map_err(|e| anyhow!("Failed to decrypt data: {}", e))
+    }
+
+    async fn set_name(&self, name: &str) -> Result<()> {
+        let routing_context = self.get_routing_context();
+        let key = self.get_dht_record().key().clone();
+        let encrypted_name = self.encrypt_aead(name.as_bytes(), None)?;
+        routing_context.set_dht_value(key, 0, encrypted_name, None).await?;
+        Ok(())
+    }
+
+    async fn get_name(&self) -> Result<String> {
+        let routing_context = self.get_routing_context();
+        let key = self.get_dht_record().key().clone();
+        let value = routing_context.get_dht_value(key, 0, false).await?;
+        match value {
+            Some(value) => {
+                let decrypted_name = self.decrypt_aead(value.data(), None)?;
+                Ok(String::from_utf8(decrypted_name).map_err(|e| anyhow!("Failed to convert DHT value to string: {}", e))?)
+            }
+            None => Err(anyhow!("Value not found")),
+        }
+    }
+
+    async fn close(&self) -> Result<()> {
+        let routing_context = self.get_routing_context();
+        let key = self.get_dht_record().key().clone();
+        routing_context.close_dht_record(key).await?;
+        Ok(())
+    }
+
+    
+    fn get_write_key(&self) -> Option<CryptoKey> {
+        unimplemented!("WIP")
+    }
+
+    async fn members(&self) -> Result<Vec<CryptoKey>> {
+        unimplemented!("WIP")
+    }
+
+    async fn join(&self) -> Result<()> {
+        unimplemented!("WIP")
+    }
+
+    async fn leave(&self) -> Result<()> {
+        unimplemented!("WIP")
+    }
+}
diff --git a/src/constants.rs b/src/constants.rs
new file mode 100644
index 0000000..1354be5
--- /dev/null
+++ b/src/constants.rs
@@ -0,0 +1,8 @@
+pub const GROUP_NOT_FOUND: &str = "Group not found";
+pub const UNABLE_TO_SET_GROUP_NAME: &str = "Unable to set group name";
+pub const UNABLE_TO_GET_GROUP_NAME: &str = "Unable to get group name";
+pub const TEST_GROUP_NAME: &str = "Test Group";
+pub const UNABLE_TO_STORE_KEYPAIR: &str = "Unable to store keypair";
+pub const FAILED_TO_LOAD_KEYPAIR: &str = "Failed to load keypair";
+pub const KEYPAIR_NOT_FOUND: &str = "Keypair not found";
+pub const FAILED_TO_DESERIALIZE_KEYPAIR: &str = "Failed to deserialize keypair";
\ No newline at end of file
diff --git a/src/group.rs b/src/group.rs
index 927a7d7..2a1b041 100644
--- a/src/group.rs
+++ b/src/group.rs
@@ -1,134 +1,90 @@
-use async_stream::stream;
-use futures_core::stream::Stream;
 use serde::{Serialize, Deserialize};
-use eyre::{Result, anyhow};
+use eyre::{Result, Error, anyhow};
 use std::sync::Arc;
 use veilid_core::{
-    CryptoKey, DHTRecordDescriptor, CryptoTyped, VeilidUpdate, VeilidConfigInner, api_startup_config, CRYPTO_KIND_VLD0, Nonce, ProtectedStore, CryptoSystemVLD0, CryptoSystem, RoutingContext, KeyPair
+    CryptoKey, DHTRecordDescriptor, CryptoTyped, CryptoSystemVLD0, RoutingContext, SharedSecret, TypedKey
 };
 
-#[derive(Serialize, Deserialize)]
-pub struct GroupKeypair {
-    pub public_key: CryptoKey,
-    pub secret_key: Option<CryptoKey>,
-    pub encryption_key: CryptoKey,
-}
+use crate::common::DHTEntity;
+use crate::repo::Repo;
 
 #[derive(Clone)]
 pub struct Group {
-    pub id: CryptoKey,
     pub dht_record: DHTRecordDescriptor,
-    pub encryption_key: CryptoTyped<CryptoKey>,
-    pub secret_key: Option<CryptoTyped<CryptoKey>>,
+    pub encryption_key: SharedSecret,
     pub routing_context: Arc<RoutingContext>,
     pub crypto_system: CryptoSystemVLD0,
+    pub repos: Vec<Repo>,
 }
 
 impl Group {
     pub fn new(
-        id: CryptoKey,
         dht_record: DHTRecordDescriptor,
-        encryption_key: CryptoTyped<CryptoKey>,
-        secret_key: Option<CryptoTyped<CryptoKey>>,
+        encryption_key: SharedSecret,
         routing_context: Arc<RoutingContext>,
         crypto_system: CryptoSystemVLD0,
     ) -> Self {
         Self {
-            id,
             dht_record,
             encryption_key,
-            secret_key,
             routing_context,
             crypto_system,
+            repos: Vec::new(), 
         }
     }
 
-    pub fn get_id(&self) -> CryptoKey {
-        self.id.clone()
+    pub fn id(&self) -> CryptoKey {
+        self.dht_record.key().value.clone()
     }
 
-    pub fn get_write_key(&self) -> Option<CryptoKey> {
-        unimplemented!("WIP")
+    pub fn owner_key(&self) -> CryptoKey {
+        self.dht_record.owner().clone()
     }
 
-    pub fn get_encryption_key(&self) -> CryptoKey {
-        self.encryption_key.value
+    pub fn owner_secret(&self) -> Option<CryptoKey> {
+        self.dht_record.owner_secret().cloned()
     }
-
-    pub async fn set_name(&self, name: &str) -> Result<()> {
-        let routing_context = &self.routing_context;
-        let key = self.dht_record.key().clone();
-        let encrypted_name = self.encrypt_aead(name.as_bytes(), None)?;
-        routing_context.set_dht_value(key, 0, encrypted_name, None).await?;
+    
+    pub async fn add_repo(&mut self, repo: Repo) -> Result<()> {
+        self.repos.push(repo);
         Ok(())
     }
 
-    pub async fn get_name(&self) -> Result<String> {
-        let routing_context = &self.routing_context;
-        let key = self.dht_record.key().clone();
-        let value = routing_context.get_dht_value(key, 0, false).await?;
-        match value {
-            Some(value) => {
-                let decrypted_name = self.decrypt_aead(value.data(), None)?;
-                Ok(String::from_utf8(decrypted_name).map_err(|e| anyhow!("Failed to convert DHT value to string: {}", e))?)
-            }
-            None => Err(anyhow!("Value not found")),
-        }
-    }
-
-    pub async fn name(&self) -> Result<String> {
-        self.get_name().await
+    pub async fn list_repos(&self) -> Vec<CryptoKey> {
+        self.repos.iter().map(|repo| repo.get_id()).collect()
     }
 
-    pub async fn members(&self) -> Result<Vec<CryptoKey>> {
-        unimplemented!("WIP")
+    pub async fn get_repo_name(&self, repo_key: CryptoKey) -> Result<String> {
+        if let Some(repo) = self.repos.iter().find(|repo| repo.get_id() == repo_key) {
+            repo.get_name().await
+        } else {
+            Err(anyhow!("Repo not found"))
+        }
     }
+}
 
-    pub async fn join(&self) -> Result<()> {
-        unimplemented!("WIP")
+impl DHTEntity for Group {
+    fn get_id(&self) -> CryptoKey {
+        self.id().clone()
     }
 
-    pub async fn leave(&self) -> Result<()> {
-        unimplemented!("WIP")
+    fn get_encryption_key(&self) -> SharedSecret {
+        self.encryption_key.clone()
     }
 
-    pub async fn close(&self) -> Result<()> {
-        let routing_context = &self.routing_context;
-        let key = self.dht_record.key().clone();
-        routing_context.close_dht_record(key).await?;
-        Ok(())
+    fn get_routing_context(&self) -> Arc<RoutingContext> {
+        self.routing_context.clone()
     }
 
-    pub fn encrypt_aead(&self, data: &[u8], associated_data: Option<&[u8]>) -> Result<Vec<u8>> {
-        let nonce = self.crypto_system.random_nonce();
-        let mut buffer = Vec::with_capacity(nonce.as_slice().len() + data.len());
-        buffer.extend_from_slice(nonce.as_slice());
-        buffer.extend_from_slice(
-            &self
-                .crypto_system
-                .encrypt_aead(data, &nonce, &self.encryption_key.value, associated_data)
-                .map_err(|e| anyhow!("Failed to encrypt data: {}", e))?,
-        );
-        Ok(buffer)
+    fn get_crypto_system(&self) -> CryptoSystemVLD0 {
+        self.crypto_system.clone()
     }
 
-    pub fn decrypt_aead(&self, data: &[u8], associated_data: Option<&[u8]>) -> Result<Vec<u8>> {
-        let nonce: [u8; 24] = data[..24].try_into().map_err(|_| anyhow!("Failed to convert nonce slice to array"))?;
-        let nonce = Nonce::new(nonce);
-        let encrypted_data = &data[24..];
-        self.crypto_system
-            .decrypt_aead(encrypted_data, &nonce, &self.encryption_key.value, associated_data)
-            .map_err(|e| anyhow!("Failed to decrypt data: {}", e))
+    fn get_dht_record(&self) -> DHTRecordDescriptor {
+        self.dht_record.clone()
     }
 
-    pub async fn store_keypair(&self, protected_store: &ProtectedStore) -> Result<()> {
-        let keypair = GroupKeypair {
-            public_key: self.id.clone(),
-            secret_key: self.secret_key.as_ref().map(|sk| sk.value.clone()),
-            encryption_key: self.encryption_key.value.clone(),
-        };
-        let keypair_data = serde_cbor::to_vec(&keypair).map_err(|e| anyhow!("Failed to serialize keypair: {}", e))?;
-        protected_store.save_user_secret(self.id.to_string(), &keypair_data).await.map_err(|e| anyhow!("Unable to store keypair: {}", e))?;
-        Ok(())
+    fn get_secret_key(&self) -> Option<CryptoKey> {
+        self.owner_secret()
     }
 }
diff --git a/src/lib.rs b/src/lib.rs
index 3e9db7b..2defe1b 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,3 +1,95 @@
 pub mod group;
 pub mod repo;
 pub mod backend;
+pub mod common;
+pub mod constants;
+
+use crate::constants::{GROUP_NOT_FOUND, UNABLE_TO_SET_GROUP_NAME, UNABLE_TO_GET_GROUP_NAME, TEST_GROUP_NAME, UNABLE_TO_STORE_KEYPAIR, FAILED_TO_LOAD_KEYPAIR, KEYPAIR_NOT_FOUND, FAILED_TO_DESERIALIZE_KEYPAIR};
+
+use crate::backend::Backend;
+use crate::common::{CommonKeypair, DHTEntity};
+use veilid_core::{
+    vld0_generate_keypair, TypedKey, CRYPTO_KIND_VLD0
+};
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use tokio::fs;
+    use tmpdir::TmpDir;
+
+    #[tokio::test]
+    async fn basic_test() {
+        let path = TmpDir::new("test_dweb_backend").await.unwrap();
+        let port = 8080;
+
+        fs::create_dir_all(path.as_ref()).await.expect("Failed to create base directory");
+
+        let mut backend = Backend::new(path.as_ref(), port).expect("Unable to create Backend");
+
+        backend.start().await.expect("Unable to start");
+        let group = backend.create_group().await.expect("Unable to create group");
+
+        group.set_name(TEST_GROUP_NAME).await.expect(UNABLE_TO_SET_GROUP_NAME);
+        let name = group.get_name().await.expect(UNABLE_TO_GET_GROUP_NAME);
+        assert_eq!(name, TEST_GROUP_NAME);
+
+        backend.stop().await.expect("Unable to stop");
+
+        backend.start().await.expect("Unable to restart");
+        let loaded_group = backend.get_group(TypedKey::new(CRYPTO_KIND_VLD0, group.id())).await.expect(GROUP_NOT_FOUND);
+
+        let protected_store = backend.get_protected_store().unwrap();
+        let keypair_data = protected_store.load_user_secret(group.id().to_string())
+            .await
+            .expect(FAILED_TO_LOAD_KEYPAIR)
+            .expect(KEYPAIR_NOT_FOUND);
+        let retrieved_keypair: CommonKeypair = serde_cbor::from_slice(&keypair_data).expect(FAILED_TO_DESERIALIZE_KEYPAIR);
+
+        // Check that the id matches group.id()
+        assert_eq!(retrieved_keypair.id, group.id());
+        
+        // Check that the public_key matches the owner public key from the DHT record
+        assert_eq!(retrieved_keypair.public_key, loaded_group.get_dht_record().owner().clone());
+
+        // Check that the secret and encryption keys match
+        assert_eq!(retrieved_keypair.secret_key, group.get_secret_key());
+        assert_eq!(retrieved_keypair.encryption_key, group.get_encryption_key());
+
+        let mut loaded_group = backend.get_group(TypedKey::new(CRYPTO_KIND_VLD0, group.id())).await.expect(GROUP_NOT_FOUND);
+
+        // Check if we can get group name
+        let group_name = loaded_group.get_name().await.expect(UNABLE_TO_GET_GROUP_NAME);
+        assert_eq!(group_name, TEST_GROUP_NAME);
+
+        // Compare the loaded group's id with the retrieved id
+        assert_eq!(loaded_group.id(), retrieved_keypair.id);
+
+        // Create a repo
+        let repo = backend.create_repo().await.expect("Unable to create repo");
+        let repo_key = repo.get_id();
+        let repo_name = "Test Repo";
+
+        // Set and get repo name
+        repo.set_name(repo_name).await.expect("Unable to set repo name");
+        let name = repo.get_name().await.expect("Unable to get repo name");
+        assert_eq!(name, repo_name);
+
+        // Add repo to group
+        loaded_group.add_repo(repo).await.expect("Unable to add repo to group");
+
+        // List known repos
+        let repos = loaded_group.list_repos().await;
+        assert!(repos.contains(&repo_key));
+
+        // Retrieve repo by key
+        let loaded_repo = backend.get_repo(repo_key.clone()).await.expect("Repo not found");
+
+        // Check if repo name is correctly retrieved
+        let retrieved_name = loaded_repo.get_name().await.expect("Unable to get repo name after restart");
+        assert_eq!(retrieved_name, repo_name);
+
+        backend.stop().await.expect("Unable to stop");
+    }
+
+}
diff --git a/src/main.rs b/src/main.rs
index 05dfef9..e2ae84e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,16 +1,21 @@
 use clap::{Command, Arg};
-use eyre::Result;
+use anyhow::{Result, anyhow};
 use xdg::BaseDirectories;
 use tokio::fs;
 use crate::backend::Backend;
-use crate::group::GroupKeypair;
+use crate::common::{CommonKeypair, DHTEntity};
+use crate::group::Group;
+use crate::repo::Repo;
+use crate::constants::{UNABLE_TO_SET_GROUP_NAME, UNABLE_TO_GET_GROUP_NAME};
 
+mod common;
 mod group;
 mod repo;
 mod backend;
+mod constants;
 
 #[tokio::main]
-async fn main() -> Result<()> {
+async fn main() -> anyhow::Result<()> {
     let matches = Command::new("Save DWeb Backend")
         .arg(Arg::new("pubkey")
             .long("pubkey")
@@ -38,6 +43,7 @@ async fn main() -> Result<()> {
 
     backend.start().await?;
 
+    // Check if keys were provided, otherwise create a new group
     if matches.contains_id("pubkey") && matches.contains_id("seckey") && matches.contains_id("enckey") {
         let pubkey = matches.get_one::<String>("pubkey").unwrap();
         let seckey = matches.get_one::<String>("seckey").unwrap();
@@ -47,56 +53,14 @@ async fn main() -> Result<()> {
         println!("Provided Encryption Key: {:?}", enckey);
     } else {
         let group = backend.create_group().await?;
-        println!("Group created with Public Key: {:?}", group.get_id());
-        println!("Group created with Secret Key: {:?}", group.secret_key.as_ref().unwrap().value);
+        println!("Group created with Record Key: {:?}", group.id());
+        println!("Group created with Secret Key: {:?}", group.get_secret_key().unwrap());
         println!("Group created with Encryption Key: {:?}", group.get_encryption_key());
     }
-
+    // Await for ctrl-c and then stop the backend
     tokio::signal::ctrl_c().await?;
 
     backend.stop().await?;
 
     Ok(())
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use tokio::fs;
-    use tmpdir::TmpDir;
-
-    #[tokio::test]
-    async fn basic_test() {
-        let path = TmpDir::new("test_dweb_backend").await.unwrap();
-        let port = 8080;
-
-        fs::create_dir_all(path.as_ref()).await.expect("Failed to create base directory");
-
-        let mut backend = Backend::new(path.as_ref(), port).expect("Unable to create Backend");
-
-        backend.start().await.expect("Unable to start");
-        let group = backend.create_group().await.expect("Unable to create group");
-
-        let group_key = group.get_id();
-        group.set_name("Test Group").await.expect("Unable to set group name");
-        let name = group.get_name().await.expect("Unable to get group name");
-        assert_eq!(name, "Test Group");
-
-        backend.stop().await.expect("Unable to stop");
-
-        backend.start().await.expect("Unable to restart");
-        let loaded_group = backend.get_group(group_key.clone()).await.expect("Group not found");
-
-        let protected_store = backend.get_protected_store().unwrap();
-        let keypair_data = protected_store.load_user_secret(group_key.to_string()).await.expect("Failed to load keypair").expect("Keypair not found");
-        let retrieved_keypair: GroupKeypair = serde_cbor::from_slice(&keypair_data).expect("Failed to deserialize keypair");
-
-        assert_eq!(retrieved_keypair.public_key, group.get_id());
-        assert_eq!(retrieved_keypair.secret_key, group.secret_key.as_ref().map(|sk| sk.value.clone()));
-        assert_eq!(retrieved_keypair.encryption_key, group.get_encryption_key());
-
-        assert_eq!(loaded_group.get_id(), retrieved_keypair.public_key);
-
-        backend.stop().await.expect("Unable to stop");
-    }
-}
+}
\ No newline at end of file
diff --git a/src/repo.rs b/src/repo.rs
index f0e75b0..3bd6292 100644
--- a/src/repo.rs
+++ b/src/repo.rs
@@ -1,17 +1,39 @@
+use crate::common::DHTEntity;
 use async_stream::stream;
-use futures_core::stream::Stream;
 use eyre::Result;
-use veilid_core::CryptoKey;
+use futures_core::stream::Stream;
+use std::sync::Arc;
+use veilid_core::{
+    CryptoKey, CryptoSystemVLD0, CryptoTyped, DHTRecordDescriptor, RoutingContext, SharedSecret,
+};
 
-pub struct Repo {}
+#[derive(Clone)]
+pub struct Repo {
+    pub id: CryptoKey,
+    pub dht_record: DHTRecordDescriptor,
+    pub encryption_key: SharedSecret,
+    pub secret_key: Option<CryptoTyped<CryptoKey>>,
+    pub routing_context: Arc<RoutingContext>,
+    pub crypto_system: CryptoSystemVLD0,
+}
 
 impl Repo {
-    pub fn new() -> Self {
-        Self {}
-    }
-
-    pub fn get_id(&self) -> CryptoKey {
-        unimplemented!("WIP")
+    pub fn new(
+        id: CryptoKey,
+        dht_record: DHTRecordDescriptor,
+        encryption_key: SharedSecret,
+        secret_key: Option<CryptoTyped<CryptoKey>>,
+        routing_context: Arc<RoutingContext>,
+        crypto_system: CryptoSystemVLD0,
+    ) -> Self {
+        Self {
+            id,
+            dht_record,
+            encryption_key,
+            secret_key,
+            routing_context,
+            crypto_system,
+        }
     }
 
     pub fn get_write_key(&self) -> Option<CryptoKey> {
@@ -40,8 +62,28 @@ impl Repo {
     }
 }
 
-impl Default for Repo {
-    fn default() -> Self {
-        Self::new()
+impl DHTEntity for Repo {
+    fn get_id(&self) -> CryptoKey {
+        self.id.clone()
+    }
+
+    fn get_encryption_key(&self) -> SharedSecret {
+        self.encryption_key.clone()
+    }
+
+    fn get_routing_context(&self) -> Arc<RoutingContext> {
+        self.routing_context.clone()
+    }
+
+    fn get_crypto_system(&self) -> CryptoSystemVLD0 {
+        self.crypto_system.clone()
+    }
+
+    fn get_dht_record(&self) -> DHTRecordDescriptor {
+        self.dht_record.clone()
+    }
+
+    fn get_secret_key(&self) -> Option<CryptoKey> {
+        self.secret_key.clone().map(|key| key.value)
     }
 }