diff --git a/compendium_v2/routes/survey_model.json b/compendium_v2/migrations/surveymodels/survey_model_2022.json
similarity index 100%
rename from compendium_v2/routes/survey_model.json
rename to compendium_v2/migrations/surveymodels/survey_model_2022.json
diff --git a/compendium_v2/routes/survey.py b/compendium_v2/routes/survey.py
index daa3921c827ec8509988f37ee377daf243cd0249..7920a581d77c56240ccdbeab8c9348f57bb3890d 100644
--- a/compendium_v2/routes/survey.py
+++ b/compendium_v2/routes/survey.py
@@ -1,8 +1,6 @@
-import json
 import logging
 from enum import Enum
-from pathlib import Path
-from typing import Any, Optional, TypedDict, List, Dict
+from typing import Any, TypedDict, List, Dict
 
 from flask import Blueprint, jsonify, request
 from sqlalchemy import select
@@ -33,7 +31,7 @@ LIST_SURVEYS_RESPONSE_SCHEMA = {
         'survey': {
             'type': 'object',
             'properties': {
-                'year': {'type': 'string'},
+                'year': {'type': 'integer'},
                 'status': {'type': 'string'},
                 'responses': {'type': 'array', 'items': {'$ref': '#/definitions/response'}},
             },
@@ -53,9 +51,9 @@ SURVEY_RESPONSE_SCHEMA = {
         'model': {'type': 'object'},
         'data': {'type': 'object'},
         'page': {'type': 'number'},
-        'verification_status': {'type': 'array', 'items': {'type': 'string'}}
+        'verification_status': {'type': 'object'}
     },
-    'required': ['year', 'status', 'responses'],
+    'required': ['model', 'data', 'page', 'verification_status'],
     'additionalProperties': False
 }
 
@@ -239,7 +237,16 @@ def try_survey(year) -> Any:
         compendium_v2.routes.survey.SURVEY_RESPONSE_SCHEMA
 
     """
-    return get_survey(year, all_visible=False)
+    survey = db.session.scalar(select(Survey).where(Survey.year == year))
+    if not survey:
+        return "Survey not found", 404
+
+    return jsonify({
+        "model": survey.survey,
+        "data": {},
+        "page": 0,
+        "verification_status": {}
+    })
 
 
 # TODO admin only
@@ -256,16 +263,10 @@ def inspect_survey(year) -> Any:
         compendium_v2.routes.survey.SURVEY_RESPONSE_SCHEMA
 
     """
-    return get_survey(year, all_visible=True)
-
-
-def get_survey(year, all_visible) -> Any:
     survey = db.session.scalar(select(Survey).where(Survey.year == year))
     if not survey:
         return "Survey not found", 404
 
-    survey_json = prepare_survey_model(survey.survey, year, all_visible)
-
     def visible_visitor(object, items):
         for key, value in items:
             if type(value) == dict:
@@ -276,12 +277,11 @@ def get_survey(year, all_visible) -> Any:
                 object['title'] = object['title'] + ' (visibleif: [' + value.replace('{', '#').replace('}', '#') + '])'
                 object[key] = 'true'
 
-    if all_visible:
-        visible_visitor(survey, survey.items())
+    visible_visitor(survey.survey, survey.survey.items())
 
     return jsonify({
-        "model": survey_json,
-        "data": None,
+        "model": survey.survey,
+        "data": {},
         "page": 0,
         "verification_status": {}
     })
@@ -312,8 +312,7 @@ def load_survey(year, nren_name) -> Any:
 
     # TODO validation (if not admin) on year (is survey open?) and nren (logged in user is part of nren?)
 
-    survey_json = prepare_survey_model(survey.survey, year)
-    data: Optional[dict] = None
+    data = {}
     page = 0
     verification_status = {}
 
@@ -335,24 +334,13 @@ def load_survey(year, nren_name) -> Any:
         verification_status = {question_name: VerificationStatus.Unverified for question_name in data.keys()}
 
     return jsonify({
-        "model": survey_json,
+        "model": survey.survey,
         "data": data,
         "page": page,
         "verification_status": verification_status
     })
 
 
-def prepare_survey_model(survey, year, all_visible=False):
-    if survey is None or survey == {}:
-        # TODO remove this at some point, its just convenient for now while we are changing the survey model a lot
-        # or is it really?? we can also keep the surveys on disk, which makes it really easy to diff, etc
-        p = Path(__file__).with_name('survey_model.json')
-        with p.open('r') as f:
-            survey = json.load(f)
-
-    return survey
-
-
 @routes.route('/save/<int:year>/<string:nren_name>', methods=['POST'])
 @common.require_accepts_json
 def save_survey(year, nren_name) -> Any:
diff --git a/survey-frontend/src/SurveyComponent.tsx b/survey-frontend/src/SurveyComponent.tsx
index e07d016a896a7bcc67465ea296559dc8bdf0dbc9..cf20f9a36efc0640e10e11a44a5076ecf6aaee28 100644
--- a/survey-frontend/src/SurveyComponent.tsx
+++ b/survey-frontend/src/SurveyComponent.tsx
@@ -117,10 +117,9 @@ function SurveyComponent({ loadFrom, saveTo = '', readonly = false}) {
     survey.setVariable('surveyyear', year);
     survey.setVariable('previousyear', parseInt(year!) - 1);
 
-    if (json['data'] !== null) {
-      survey.data = json['data'];
-      survey.clearIncorrectValues(true);  // TODO test if this really removes all old values and such
-    }
+    survey.data = json['data'];
+    survey.clearIncorrectValues(true);  // TODO test if this really removes all old values and such
+
     survey.currentPageNo = json['page'];
 
     survey.addNavigationItem({
diff --git a/test/conftest.py b/test/conftest.py
index 8fdd0c86cec496325f0f7e6b8bb5a0b3420ba215..fa53adf02f5980e1f43bb42020b82baad7ab484e 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -4,8 +4,8 @@ import pytest
 import random
 
 import compendium_v2
-from compendium_v2.db import db, model
-from compendium_v2.survey_db import model as survey_model
+from compendium_v2.db import db, model, survey_model
+from compendium_v2.survey_db import model as survey_db_model
 
 
 def _test_data_csv(filename):
@@ -113,6 +113,31 @@ def test_staff_data(app):
         db.session.commit()
 
 
+@pytest.fixture
+def test_survey_data(app):
+    with app.app_context():
+        nren_names = ['nren1', 'nren2', 'nren3', 'nren4']
+        nren_dict = {nren_name: model.NREN(name=nren_name, country='country') for nren_name in nren_names}
+        db.session.add_all(nren_dict.values())
+
+        survey2021 = survey_model.Survey(year=2021, survey={}, status=survey_model.SurveyStatus.published)
+        survey2022 = survey_model.Survey(
+            year=2022,
+            survey={'part1': [{'title': 'ha', 'visibleIf': 'false'}]},
+            status=survey_model.SurveyStatus.published
+        )
+        db.session.add_all([survey2021, survey2022])
+
+        db.session.add(survey_model.SurveyResponse(
+            nren=nren_dict['nren1'],
+            survey=survey2022,
+            answers={},
+            status=survey_model.ResponseStatus.checked
+        ))
+
+        db.session.commit()
+
+
 @pytest.fixture
 def app(dummy_config):
     app = compendium_v2._create_app_with_db(dummy_config)
@@ -123,7 +148,7 @@ def app(dummy_config):
 
 @pytest.fixture
 def app_with_survey_db(dummy_config):
-    dummy_config['SQLALCHEMY_BINDS'] = {survey_model.SURVEY_DB_BIND: dummy_config['SURVEY_DATABASE_URI']}
+    dummy_config['SQLALCHEMY_BINDS'] = {survey_db_model.SURVEY_DB_BIND: dummy_config['SURVEY_DATABASE_URI']}
     app = compendium_v2._create_app_with_db(dummy_config)
     with app.app_context():
         db.create_all()
diff --git a/test/test_survey.py b/test/test_survey.py
new file mode 100644
index 0000000000000000000000000000000000000000..b4b4d4f6aa64d0d62bc353139cf131988732ac05
--- /dev/null
+++ b/test/test_survey.py
@@ -0,0 +1,123 @@
+import json
+import jsonschema
+from compendium_v2.routes.survey import LIST_SURVEYS_RESPONSE_SCHEMA, SURVEY_RESPONSE_SCHEMA, VerificationStatus
+
+
+def test_survey_route_list_response(client, test_survey_data):
+    rv = client.get(
+        '/api/survey/list',
+        headers={'Accept': ['application/json']})
+    assert rv.status_code == 200
+    result = json.loads(rv.data.decode('utf-8'))
+    jsonschema.validate(result, LIST_SURVEYS_RESPONSE_SCHEMA)
+    assert result
+
+
+def test_survey_route_new(client, test_survey_data):
+    rv = client.post(
+        '/api/survey/new',
+        headers={'Accept': ['application/json']})
+    assert rv.status_code == 200
+    result = json.loads(rv.data.decode('utf-8'))
+    assert result == {'success': True}
+
+    rv = client.post(
+        '/api/survey/new',
+        headers={'Accept': ['application/json']})
+    assert rv.status_code != 200
+
+
+def test_survey_route_open_close(client, test_survey_data):
+    rv = client.post(
+        '/api/survey/new',
+        headers={'Accept': ['application/json']})
+    assert rv.status_code == 200
+    result = json.loads(rv.data.decode('utf-8'))
+    assert result == {'success': True}
+
+    rv = client.post(
+        '/api/survey/open/2023',
+        headers={'Accept': ['application/json']})
+    assert rv.status_code == 200
+    result = json.loads(rv.data.decode('utf-8'))
+    assert result == {'success': True}
+
+    rv = client.post(
+        '/api/survey/open/2023',
+        headers={'Accept': ['application/json']})
+    assert rv.status_code != 200
+
+    rv = client.post(
+        '/api/survey/close/2023',
+        headers={'Accept': ['application/json']})
+    assert rv.status_code == 200
+    result = json.loads(rv.data.decode('utf-8'))
+    assert result == {'success': True}
+
+    rv = client.post(
+        '/api/survey/close/2023',
+        headers={'Accept': ['application/json']})
+    assert rv.status_code != 200
+
+
+def test_survey_route_publish(client, test_survey_data):
+    rv = client.post(
+        '/api/survey/publish/2022',
+        headers={'Accept': ['application/json']})
+    assert rv.status_code == 200
+    result = json.loads(rv.data.decode('utf-8'))
+    assert result == {'success': True}
+
+
+def test_survey_route_try_response(client, test_survey_data):
+    rv = client.get(
+        '/api/survey/try/2022',
+        headers={'Accept': ['application/json']})
+    assert rv.status_code == 200
+    result = json.loads(rv.data.decode('utf-8'))
+    jsonschema.validate(result, SURVEY_RESPONSE_SCHEMA)
+    assert result
+
+
+def test_survey_route_inspect_response(client, test_survey_data):
+    rv = client.get(
+        '/api/survey/inspect/2022',
+        headers={'Accept': ['application/json']})
+    assert rv.status_code == 200
+    result = json.loads(rv.data.decode('utf-8'))
+    jsonschema.validate(result, SURVEY_RESPONSE_SCHEMA)
+    assert result
+
+
+def test_survey_route_save_load_response(client, test_survey_data):
+    rv = client.post(
+        '/api/survey/save/2021/nren2',
+        headers={'Accept': ['application/json']},
+        json={
+            'data': {'q1': 'yes', 'q2': ['no']},
+            'page': 3,
+            'verification_status': {'q1': VerificationStatus.Verified}
+        })
+    assert rv.status_code == 200
+    result = json.loads(rv.data.decode('utf-8'))
+    assert result == {'success': True}
+
+    rv = client.get(
+        '/api/survey/load/2021/nren2',
+        headers={'Accept': ['application/json']})
+    assert rv.status_code == 200
+    result = json.loads(rv.data.decode('utf-8'))
+    jsonschema.validate(result, SURVEY_RESPONSE_SCHEMA)
+    assert result['page'] == 3
+    assert result['data'] == {'q1': 'yes', 'q2': ['no']}
+    assert result['verification_status'] == {'q1': VerificationStatus.Verified}
+
+    rv = client.get(
+        '/api/survey/load/2022/nren2',
+        headers={'Accept': ['application/json']})
+    assert rv.status_code == 200
+    result = json.loads(rv.data.decode('utf-8'))
+    jsonschema.validate(result, SURVEY_RESPONSE_SCHEMA)
+    assert result['page'] == 0
+    assert result['data'] == {'q1': 'yes', 'q2': ['no']}
+    assert result['verification_status'] == {'q1': VerificationStatus.Unverified, 'q2': VerificationStatus.Unverified}