diff --git a/src/data.rs b/src/data.rs
index d9b2b1b1..98779937 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -4,8 +4,10 @@
 // SPDX-License-Identifier: AGPL-3.0-or-later
 
 //! App data: redis cache, database connections, etc.
-use std::sync::Arc;
+use std::sync::{RwLock, Arc};
+use std::collections::HashMap;
 use std::thread;
+use std::time::Duration;
 
 use actix::prelude::*;
 use argon2_creds::{Config, ConfigBuilder, PasswordPolicy};
@@ -28,7 +30,12 @@ use libmcaptcha::{
     pow::Work,
     system::{System, SystemBuilder},
 };
+use reqwest::Client;
+use serde::{Serialize, Deserialize};
+use tokio::task::JoinHandle;
+use tokio::time::sleep;
 
+use crate::AppData;
 use crate::db::{self, BoxDB};
 use crate::errors::ServiceResult;
 use crate::settings::Settings;
@@ -242,6 +249,95 @@ impl Data {
             None
         }
     }
+
+    async fn upload_survey_job(&self) -> ServiceResult<()> {
+        unimplemented!()
+    }
+    async fn register_survey(&self) -> ServiceResult<()> {
+        unimplemented!()
+    }
+}
+
+#[async_trait::async_trait]
+trait SurveyClientTrait {
+    async fn start_job(&self, data: AppData) -> ServiceResult<JoinHandle<()>>;
+    async fn register(&self, data: &AppData) -> ServiceResult<()>;
+}
+
+#[derive(Clone, Debug, Default)]
+struct SecretsStore {
+    store: Arc<RwLock<HashMap<String, String>>>
+}
+
+impl SecretsStore {
+    fn get(&self, key: &str) -> Option<String> {
+        let r = self.store.read().unwrap();
+        r.get(key).map(|x| x.to_owned())
+    }
+
+    fn set(&self, key: String, value: String) {
+        let mut w = self.store.write().unwrap();
+        w.insert(key,value );
+        drop(w);
+    }
+}
+
+
+
+struct Survey {
+    settings: Settings,
+    client: Client,
+    secrets: SecretsStore,
+}
+impl Survey {
+    fn new(settings: Settings) -> Self {
+        Survey {
+            client: Client::new(),
+            settings,
+            secrets: SecretsStore::default(),
+        }
+    }
+}
+
+#[async_trait::async_trait]
+impl  SurveyClientTrait for Survey {
+    async fn start_job(&self, data: AppData) -> ServiceResult<JoinHandle<()>> {
+        let fut = async move {
+            loop {
+                sleep(Duration::new(data.settings.survey.rate_limit, 0)).await;
+//                if let Err(e) = Self::delete_demo_user(&data).await {
+//                    log::error!("Error while deleting demo user: {:?}", e);
+//                }
+//                if let Err(e) = Self::register_demo_user(&data).await {
+//                    log::error!("Error while registering demo user: {:?}", e);
+//                }
+            }
+        };
+        let handle = tokio::spawn(fut);
+        Ok(handle)
+
+    }
+    async fn register(&self, data: &AppData) -> ServiceResult<()> {
+        let protocol = if self.settings.server.proxy_has_tls {
+            "https://"
+        } else {
+            "http://"
+        };
+        #[derive(Serialize)]
+        struct MCaptchaInstance {
+            url: url::Url,
+        }
+
+        let payload =  MCaptchaInstance {
+            url: url::Url::parse(&format!("{protocol}{}", self.settings.server.domain))?,
+        };
+        for url in self.settings.survey.nodes.iter() {
+            self.client.post(url.clone()).json(&payload).send().await.unwrap();
+        }
+        Ok(())
+    }
+
+    
 }
 
 /// Mailer data type AsyncSmtpTransport<Tokio1Executor>