From ed6677977014e0b2c21ac04b195c2df73122754d Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Tue, 24 Oct 2023 01:45:24 +0200
Subject: [PATCH 01/24] ch/initial commit

---
 Makefile                                      |   6 +
 frontend/app/.gitignore                       | 861 ++++++++++++++++++
 frontend/app/.metadata                        |  45 +
 frontend/app/README.md                        |  16 +
 frontend/app/analysis_options.yaml            |  28 +
 frontend/app/android/.gitignore               |  13 +
 frontend/app/android/app/build.gradle         |  67 ++
 .../android/app/src/debug/AndroidManifest.xml |   7 +
 .../android/app/src/main/AndroidManifest.xml  |  33 +
 .../kotlin/com/example/app/MainActivity.kt    |   6 +
 .../res/drawable-v21/launch_background.xml    |  12 +
 .../main/res/drawable/launch_background.xml   |  12 +
 .../src/main/res/mipmap-hdpi/ic_launcher.png  | Bin 0 -> 544 bytes
 .../src/main/res/mipmap-mdpi/ic_launcher.png  | Bin 0 -> 442 bytes
 .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 721 bytes
 .../main/res/mipmap-xxhdpi/ic_launcher.png    | Bin 0 -> 1031 bytes
 .../main/res/mipmap-xxxhdpi/ic_launcher.png   | Bin 0 -> 1443 bytes
 .../app/src/main/res/values-night/styles.xml  |  18 +
 .../app/src/main/res/values/styles.xml        |  18 +
 .../app/src/profile/AndroidManifest.xml       |   7 +
 frontend/app/android/build.gradle             |  31 +
 frontend/app/android/gradle.properties        |   3 +
 .../gradle/wrapper/gradle-wrapper.properties  |   5 +
 frontend/app/android/settings.gradle          |  20 +
 frontend/app/ios/.gitignore                   |  34 +
 .../app/ios/Flutter/AppFrameworkInfo.plist    |  26 +
 frontend/app/ios/Flutter/Debug.xcconfig       |   1 +
 frontend/app/ios/Flutter/Release.xcconfig     |   1 +
 .../app/ios/Runner.xcodeproj/project.pbxproj  | 614 +++++++++++++
 .../contents.xcworkspacedata                  |   7 +
 .../xcshareddata/IDEWorkspaceChecks.plist     |   8 +
 .../xcshareddata/WorkspaceSettings.xcsettings |   8 +
 .../xcshareddata/xcschemes/Runner.xcscheme    |  98 ++
 .../contents.xcworkspacedata                  |   7 +
 .../xcshareddata/IDEWorkspaceChecks.plist     |   8 +
 .../xcshareddata/WorkspaceSettings.xcsettings |   8 +
 frontend/app/ios/Runner/AppDelegate.swift     |  13 +
 .../AppIcon.appiconset/Contents.json          | 122 +++
 .../Icon-App-1024x1024@1x.png                 | Bin 0 -> 10932 bytes
 .../AppIcon.appiconset/Icon-App-20x20@1x.png  | Bin 0 -> 295 bytes
 .../AppIcon.appiconset/Icon-App-20x20@2x.png  | Bin 0 -> 406 bytes
 .../AppIcon.appiconset/Icon-App-20x20@3x.png  | Bin 0 -> 450 bytes
 .../AppIcon.appiconset/Icon-App-29x29@1x.png  | Bin 0 -> 282 bytes
 .../AppIcon.appiconset/Icon-App-29x29@2x.png  | Bin 0 -> 462 bytes
 .../AppIcon.appiconset/Icon-App-29x29@3x.png  | Bin 0 -> 704 bytes
 .../AppIcon.appiconset/Icon-App-40x40@1x.png  | Bin 0 -> 406 bytes
 .../AppIcon.appiconset/Icon-App-40x40@2x.png  | Bin 0 -> 586 bytes
 .../AppIcon.appiconset/Icon-App-40x40@3x.png  | Bin 0 -> 862 bytes
 .../AppIcon.appiconset/Icon-App-60x60@2x.png  | Bin 0 -> 862 bytes
 .../AppIcon.appiconset/Icon-App-60x60@3x.png  | Bin 0 -> 1674 bytes
 .../AppIcon.appiconset/Icon-App-76x76@1x.png  | Bin 0 -> 762 bytes
 .../AppIcon.appiconset/Icon-App-76x76@2x.png  | Bin 0 -> 1226 bytes
 .../Icon-App-83.5x83.5@2x.png                 | Bin 0 -> 1418 bytes
 .../LaunchImage.imageset/Contents.json        |  23 +
 .../LaunchImage.imageset/LaunchImage.png      | Bin 0 -> 68 bytes
 .../LaunchImage.imageset/LaunchImage@2x.png   | Bin 0 -> 68 bytes
 .../LaunchImage.imageset/LaunchImage@3x.png   | Bin 0 -> 68 bytes
 .../LaunchImage.imageset/README.md            |   5 +
 .../Runner/Base.lproj/LaunchScreen.storyboard |  37 +
 .../app/ios/Runner/Base.lproj/Main.storyboard |  26 +
 frontend/app/ios/Runner/Info.plist            |  49 +
 .../app/ios/Runner/Runner-Bridging-Header.h   |   1 +
 .../app/ios/RunnerTests/RunnerTests.swift     |  12 +
 frontend/app/lib/gapi/client.dart             |  45 +
 frontend/app/lib/main.dart                    |   7 +
 frontend/app/lib/pages/main_screen.dart       |  16 +
 frontend/app/lib/pb/account.pb.dart           | 159 ++++
 frontend/app/lib/pb/account.pbenum.dart       |  11 +
 frontend/app/lib/pb/account.pbjson.dart       |  52 ++
 frontend/app/lib/pb/account.pbserver.dart     |  14 +
 frontend/app/lib/pb/account_info.pb.dart      | 289 ++++++
 frontend/app/lib/pb/account_info.pbenum.dart  |  11 +
 frontend/app/lib/pb/account_info.pbjson.dart  |  64 ++
 .../app/lib/pb/account_info.pbserver.dart     |  14 +
 frontend/app/lib/pb/document.pb.dart          | 259 ++++++
 frontend/app/lib/pb/document.pbenum.dart      |  11 +
 frontend/app/lib/pb/document.pbjson.dart      |  55 ++
 frontend/app/lib/pb/document.pbserver.dart    |  14 +
 .../lib/pb/google/protobuf/timestamp.pb.dart  | 188 ++++
 .../pb/google/protobuf/timestamp.pbenum.dart  |  11 +
 .../pb/google/protobuf/timestamp.pbjson.dart  |  29 +
 .../lib/pb/google/protobuf/timestamp.proto    | 144 +++
 frontend/app/lib/pb/payment.pb.dart           | 257 ++++++
 frontend/app/lib/pb/payment.pbenum.dart       |  11 +
 frontend/app/lib/pb/payment.pbjson.dart       |  66 ++
 frontend/app/lib/pb/payment.pbserver.dart     |  14 +
 frontend/app/lib/pb/person.pb.dart            | 245 +++++
 frontend/app/lib/pb/person.pbenum.dart        |  11 +
 frontend/app/lib/pb/person.pbjson.dart        |  57 ++
 frontend/app/lib/pb/person.pbserver.dart      |  14 +
 frontend/app/lib/pb/returns_log.pb.dart       | 173 ++++
 frontend/app/lib/pb/returns_log.pbenum.dart   |  11 +
 frontend/app/lib/pb/returns_log.pbjson.dart   |  48 +
 frontend/app/lib/pb/returns_log.pbserver.dart |  14 +
 frontend/app/lib/pb/rpc_block_session.pb.dart | 132 +++
 .../app/lib/pb/rpc_block_session.pbenum.dart  |  11 +
 .../app/lib/pb/rpc_block_session.pbjson.dart  |  49 +
 .../lib/pb/rpc_block_session.pbserver.dart    |  14 +
 .../app/lib/pb/rpc_create_account.pb.dart     | 136 +++
 .../app/lib/pb/rpc_create_account.pbenum.dart |  11 +
 .../app/lib/pb/rpc_create_account.pbjson.dart |  47 +
 .../lib/pb/rpc_create_account.pbserver.dart   |  14 +
 .../lib/pb/rpc_create_account_info.pb.dart    | 252 +++++
 .../pb/rpc_create_account_info.pbenum.dart    |  11 +
 .../pb/rpc_create_account_info.pbjson.dart    |  67 ++
 .../pb/rpc_create_account_info.pbserver.dart  |  14 +
 .../app/lib/pb/rpc_create_payment.pb.dart     | 235 +++++
 .../app/lib/pb/rpc_create_payment.pbenum.dart |  11 +
 .../app/lib/pb/rpc_create_payment.pbjson.dart |  71 ++
 .../lib/pb/rpc_create_payment.pbserver.dart   |  14 +
 frontend/app/lib/pb/rpc_create_person.pb.dart | 224 +++++
 .../app/lib/pb/rpc_create_person.pbenum.dart  |  11 +
 .../app/lib/pb/rpc_create_person.pbjson.dart  |  60 ++
 .../lib/pb/rpc_create_person.pbserver.dart    |  14 +
 .../app/lib/pb/rpc_delete_document.pb.dart    | 133 +++
 .../lib/pb/rpc_delete_document.pbenum.dart    |  11 +
 .../lib/pb/rpc_delete_document.pbjson.dart    |  45 +
 .../lib/pb/rpc_delete_document.pbserver.dart  |  14 +
 .../app/lib/pb/rpc_delete_payment.pb.dart     | 133 +++
 .../app/lib/pb/rpc_delete_payment.pbenum.dart |  11 +
 .../app/lib/pb/rpc_delete_payment.pbjson.dart |  45 +
 .../lib/pb/rpc_delete_payment.pbserver.dart   |  14 +
 frontend/app/lib/pb/rpc_delete_person.pb.dart | 133 +++
 .../app/lib/pb/rpc_delete_person.pbenum.dart  |  11 +
 .../app/lib/pb/rpc_delete_person.pbjson.dart  |  45 +
 .../lib/pb/rpc_delete_person.pbserver.dart    |  14 +
 frontend/app/lib/pb/rpc_get_account.pb.dart   | 123 +++
 .../app/lib/pb/rpc_get_account.pbenum.dart    |  11 +
 .../app/lib/pb/rpc_get_account.pbjson.dart    |  44 +
 .../app/lib/pb/rpc_get_account.pbserver.dart  |  14 +
 .../app/lib/pb/rpc_get_account_info.pb.dart   | 123 +++
 .../lib/pb/rpc_get_account_info.pbenum.dart   |  11 +
 .../lib/pb/rpc_get_account_info.pbjson.dart   |  45 +
 .../lib/pb/rpc_get_account_info.pbserver.dart |  14 +
 frontend/app/lib/pb/rpc_get_payment.pb.dart   | 123 +++
 .../app/lib/pb/rpc_get_payment.pbenum.dart    |  11 +
 .../app/lib/pb/rpc_get_payment.pbjson.dart    |  44 +
 .../app/lib/pb/rpc_get_payment.pbserver.dart  |  14 +
 frontend/app/lib/pb/rpc_get_person.pb.dart    | 123 +++
 .../app/lib/pb/rpc_get_person.pbenum.dart     |  11 +
 .../app/lib/pb/rpc_get_person.pbjson.dart     |  43 +
 .../app/lib/pb/rpc_get_person.pbserver.dart   |  14 +
 .../app/lib/pb/rpc_list_account_info.pb.dart  | 128 +++
 .../lib/pb/rpc_list_account_info.pbenum.dart  |  11 +
 .../lib/pb/rpc_list_account_info.pbjson.dart  |  47 +
 .../pb/rpc_list_account_info.pbserver.dart    |  14 +
 frontend/app/lib/pb/rpc_list_accounts.pb.dart | 128 +++
 .../app/lib/pb/rpc_list_accounts.pbenum.dart  |  11 +
 .../app/lib/pb/rpc_list_accounts.pbjson.dart  |  47 +
 .../lib/pb/rpc_list_accounts.pbserver.dart    |  14 +
 frontend/app/lib/pb/rpc_list_payments.pb.dart | 115 +++
 .../app/lib/pb/rpc_list_payments.pbenum.dart  |  11 +
 .../app/lib/pb/rpc_list_payments.pbjson.dart  |  45 +
 .../lib/pb/rpc_list_payments.pbserver.dart    |  14 +
 frontend/app/lib/pb/rpc_list_persons.pb.dart  | 115 +++
 .../app/lib/pb/rpc_list_persons.pbenum.dart   |  11 +
 .../app/lib/pb/rpc_list_persons.pbjson.dart   |  45 +
 .../app/lib/pb/rpc_list_persons.pbserver.dart |  14 +
 .../rpc_list_returns_log_by_person_id.pb.dart | 115 +++
 ..._list_returns_log_by_person_id.pbenum.dart |  11 +
 ..._list_returns_log_by_person_id.pbjson.dart |  45 +
 ...ist_returns_log_by_person_id.pbserver.dart |  14 +
 frontend/app/lib/pb/rpc_list_sessions.pb.dart | 115 +++
 .../app/lib/pb/rpc_list_sessions.pbenum.dart  |  11 +
 .../app/lib/pb/rpc_list_sessions.pbjson.dart  |  45 +
 .../lib/pb/rpc_list_sessions.pbserver.dart    |  14 +
 frontend/app/lib/pb/rpc_login.pb.dart         | 209 +++++
 frontend/app/lib/pb/rpc_login.pbenum.dart     |  11 +
 frontend/app/lib/pb/rpc_login.pbjson.dart     |  70 ++
 frontend/app/lib/pb/rpc_login.pbserver.dart   |  14 +
 frontend/app/lib/pb/rpc_refresh_token.pb.dart | 136 +++
 .../app/lib/pb/rpc_refresh_token.pbenum.dart  |  11 +
 .../app/lib/pb/rpc_refresh_token.pbjson.dart  |  72 ++
 .../lib/pb/rpc_refresh_token.pbserver.dart    |  14 +
 .../app/lib/pb/rpc_update_account.pb.dart     | 151 +++
 .../app/lib/pb/rpc_update_account.pbenum.dart |  11 +
 .../app/lib/pb/rpc_update_account.pbjson.dart |  53 ++
 .../lib/pb/rpc_update_account.pbserver.dart   |  14 +
 .../lib/pb/rpc_update_account_info.pb.dart    | 238 +++++
 .../pb/rpc_update_account_info.pbenum.dart    |  11 +
 .../pb/rpc_update_account_info.pbjson.dart    |  70 ++
 .../pb/rpc_update_account_info.pbserver.dart  |  14 +
 .../lib/pb/rpc_update_account_privacy.pb.dart | 137 +++
 .../pb/rpc_update_account_privacy.pbenum.dart |  11 +
 .../pb/rpc_update_account_privacy.pbjson.dart |  49 +
 .../rpc_update_account_privacy.pbserver.dart  |  14 +
 .../app/lib/pb/rpc_update_payment.pb.dart     | 235 +++++
 .../app/lib/pb/rpc_update_payment.pbenum.dart |  11 +
 .../app/lib/pb/rpc_update_payment.pbjson.dart |  73 ++
 .../lib/pb/rpc_update_payment.pbserver.dart   |  14 +
 frontend/app/lib/pb/rpc_update_person.pb.dart | 224 +++++
 .../app/lib/pb/rpc_update_person.pbenum.dart  |  11 +
 .../app/lib/pb/rpc_update_person.pbjson.dart  |  70 ++
 .../lib/pb/rpc_update_person.pbserver.dart    |  14 +
 .../app/lib/pb/rpc_upload_document.pb.dart    | 151 +++
 .../lib/pb/rpc_upload_document.pbenum.dart    |  11 +
 .../lib/pb/rpc_upload_document.pbjson.dart    |  52 ++
 .../lib/pb/rpc_upload_document.pbserver.dart  |  14 +
 frontend/app/lib/pb/rpc_verify_email.pb.dart  | 133 +++
 .../app/lib/pb/rpc_verify_email.pbenum.dart   |  11 +
 .../app/lib/pb/rpc_verify_email.pbjson.dart   |  46 +
 .../app/lib/pb/rpc_verify_email.pbserver.dart |  14 +
 frontend/app/lib/pb/service_df.pb.dart        | 131 +++
 frontend/app/lib/pb/service_df.pbenum.dart    |  11 +
 frontend/app/lib/pb/service_df.pbjson.dart    | 232 +++++
 frontend/app/lib/pb/service_df.pbserver.dart  | 147 +++
 frontend/app/lib/pb/session.pb.dart           | 173 ++++
 frontend/app/lib/pb/session.pbenum.dart       |  11 +
 frontend/app/lib/pb/session.pbjson.dart       |  51 ++
 frontend/app/lib/pb/session.pbserver.dart     |  14 +
 frontend/app/linux/.gitignore                 |   1 +
 frontend/app/linux/CMakeLists.txt             | 139 +++
 frontend/app/linux/flutter/CMakeLists.txt     |  88 ++
 .../flutter/generated_plugin_registrant.cc    |  11 +
 .../flutter/generated_plugin_registrant.h     |  15 +
 .../app/linux/flutter/generated_plugins.cmake |  23 +
 frontend/app/linux/main.cc                    |   6 +
 frontend/app/linux/my_application.cc          | 104 +++
 frontend/app/linux/my_application.h           |  18 +
 frontend/app/macos/.gitignore                 |   7 +
 .../app/macos/Flutter/Flutter-Debug.xcconfig  |   1 +
 .../macos/Flutter/Flutter-Release.xcconfig    |   1 +
 .../macos/Runner.xcodeproj/project.pbxproj    | 695 ++++++++++++++
 .../xcshareddata/IDEWorkspaceChecks.plist     |   8 +
 .../xcshareddata/xcschemes/Runner.xcscheme    |  98 ++
 .../contents.xcworkspacedata                  |   7 +
 .../xcshareddata/IDEWorkspaceChecks.plist     |   8 +
 frontend/app/macos/Runner/AppDelegate.swift   |   9 +
 .../AppIcon.appiconset/Contents.json          |  68 ++
 .../AppIcon.appiconset/app_icon_1024.png      | Bin 0 -> 102994 bytes
 .../AppIcon.appiconset/app_icon_128.png       | Bin 0 -> 5680 bytes
 .../AppIcon.appiconset/app_icon_16.png        | Bin 0 -> 520 bytes
 .../AppIcon.appiconset/app_icon_256.png       | Bin 0 -> 14142 bytes
 .../AppIcon.appiconset/app_icon_32.png        | Bin 0 -> 1066 bytes
 .../AppIcon.appiconset/app_icon_512.png       | Bin 0 -> 36406 bytes
 .../AppIcon.appiconset/app_icon_64.png        | Bin 0 -> 2218 bytes
 .../app/macos/Runner/Base.lproj/MainMenu.xib  | 343 +++++++
 .../app/macos/Runner/Configs/AppInfo.xcconfig |  14 +
 .../app/macos/Runner/Configs/Debug.xcconfig   |   2 +
 .../app/macos/Runner/Configs/Release.xcconfig |   2 +
 .../macos/Runner/Configs/Warnings.xcconfig    |  13 +
 .../macos/Runner/DebugProfile.entitlements    |  12 +
 frontend/app/macos/Runner/Info.plist          |  32 +
 .../app/macos/Runner/MainFlutterWindow.swift  |  15 +
 .../app/macos/Runner/Release.entitlements     |   8 +
 .../app/macos/RunnerTests/RunnerTests.swift   |  12 +
 frontend/app/pubspec.lock                     | 300 ++++++
 frontend/app/pubspec.yaml                     |  95 ++
 frontend/app/web/favicon.png                  | Bin 0 -> 917 bytes
 frontend/app/web/icons/Icon-192.png           | Bin 0 -> 5292 bytes
 frontend/app/web/icons/Icon-512.png           | Bin 0 -> 8252 bytes
 frontend/app/web/icons/Icon-maskable-192.png  | Bin 0 -> 5594 bytes
 frontend/app/web/icons/Icon-maskable-512.png  | Bin 0 -> 20998 bytes
 frontend/app/web/index.html                   |  59 ++
 frontend/app/web/manifest.json                |  35 +
 frontend/app/windows/.gitignore               |  17 +
 frontend/app/windows/CMakeLists.txt           | 102 +++
 frontend/app/windows/flutter/CMakeLists.txt   | 104 +++
 .../flutter/generated_plugin_registrant.cc    |  11 +
 .../flutter/generated_plugin_registrant.h     |  15 +
 .../windows/flutter/generated_plugins.cmake   |  23 +
 frontend/app/windows/runner/CMakeLists.txt    |  40 +
 frontend/app/windows/runner/Runner.rc         | 121 +++
 .../app/windows/runner/flutter_window.cpp     |  71 ++
 frontend/app/windows/runner/flutter_window.h  |  33 +
 frontend/app/windows/runner/main.cpp          |  43 +
 frontend/app/windows/runner/resource.h        |  16 +
 .../app/windows/runner/resources/app_icon.ico | Bin 0 -> 33772 bytes
 .../app/windows/runner/runner.exe.manifest    |  20 +
 frontend/app/windows/runner/utils.cpp         |  65 ++
 frontend/app/windows/runner/utils.h           |  19 +
 frontend/app/windows/runner/win32_window.cpp  | 288 ++++++
 frontend/app/windows/runner/win32_window.h    | 102 +++
 273 files changed, 15048 insertions(+)
 create mode 100644 frontend/app/.gitignore
 create mode 100644 frontend/app/.metadata
 create mode 100644 frontend/app/README.md
 create mode 100644 frontend/app/analysis_options.yaml
 create mode 100644 frontend/app/android/.gitignore
 create mode 100644 frontend/app/android/app/build.gradle
 create mode 100644 frontend/app/android/app/src/debug/AndroidManifest.xml
 create mode 100644 frontend/app/android/app/src/main/AndroidManifest.xml
 create mode 100644 frontend/app/android/app/src/main/kotlin/com/example/app/MainActivity.kt
 create mode 100644 frontend/app/android/app/src/main/res/drawable-v21/launch_background.xml
 create mode 100644 frontend/app/android/app/src/main/res/drawable/launch_background.xml
 create mode 100644 frontend/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
 create mode 100644 frontend/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
 create mode 100644 frontend/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
 create mode 100644 frontend/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
 create mode 100644 frontend/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
 create mode 100644 frontend/app/android/app/src/main/res/values-night/styles.xml
 create mode 100644 frontend/app/android/app/src/main/res/values/styles.xml
 create mode 100644 frontend/app/android/app/src/profile/AndroidManifest.xml
 create mode 100644 frontend/app/android/build.gradle
 create mode 100644 frontend/app/android/gradle.properties
 create mode 100644 frontend/app/android/gradle/wrapper/gradle-wrapper.properties
 create mode 100644 frontend/app/android/settings.gradle
 create mode 100644 frontend/app/ios/.gitignore
 create mode 100644 frontend/app/ios/Flutter/AppFrameworkInfo.plist
 create mode 100644 frontend/app/ios/Flutter/Debug.xcconfig
 create mode 100644 frontend/app/ios/Flutter/Release.xcconfig
 create mode 100644 frontend/app/ios/Runner.xcodeproj/project.pbxproj
 create mode 100644 frontend/app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
 create mode 100644 frontend/app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
 create mode 100644 frontend/app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
 create mode 100644 frontend/app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
 create mode 100644 frontend/app/ios/Runner.xcworkspace/contents.xcworkspacedata
 create mode 100644 frontend/app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
 create mode 100644 frontend/app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
 create mode 100644 frontend/app/ios/Runner/AppDelegate.swift
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
 create mode 100644 frontend/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
 create mode 100644 frontend/app/ios/Runner/Base.lproj/LaunchScreen.storyboard
 create mode 100644 frontend/app/ios/Runner/Base.lproj/Main.storyboard
 create mode 100644 frontend/app/ios/Runner/Info.plist
 create mode 100644 frontend/app/ios/Runner/Runner-Bridging-Header.h
 create mode 100644 frontend/app/ios/RunnerTests/RunnerTests.swift
 create mode 100644 frontend/app/lib/gapi/client.dart
 create mode 100644 frontend/app/lib/main.dart
 create mode 100644 frontend/app/lib/pages/main_screen.dart
 create mode 100644 frontend/app/lib/pb/account.pb.dart
 create mode 100644 frontend/app/lib/pb/account.pbenum.dart
 create mode 100644 frontend/app/lib/pb/account.pbjson.dart
 create mode 100644 frontend/app/lib/pb/account.pbserver.dart
 create mode 100644 frontend/app/lib/pb/account_info.pb.dart
 create mode 100644 frontend/app/lib/pb/account_info.pbenum.dart
 create mode 100644 frontend/app/lib/pb/account_info.pbjson.dart
 create mode 100644 frontend/app/lib/pb/account_info.pbserver.dart
 create mode 100644 frontend/app/lib/pb/document.pb.dart
 create mode 100644 frontend/app/lib/pb/document.pbenum.dart
 create mode 100644 frontend/app/lib/pb/document.pbjson.dart
 create mode 100644 frontend/app/lib/pb/document.pbserver.dart
 create mode 100644 frontend/app/lib/pb/google/protobuf/timestamp.pb.dart
 create mode 100644 frontend/app/lib/pb/google/protobuf/timestamp.pbenum.dart
 create mode 100644 frontend/app/lib/pb/google/protobuf/timestamp.pbjson.dart
 create mode 100644 frontend/app/lib/pb/google/protobuf/timestamp.proto
 create mode 100644 frontend/app/lib/pb/payment.pb.dart
 create mode 100644 frontend/app/lib/pb/payment.pbenum.dart
 create mode 100644 frontend/app/lib/pb/payment.pbjson.dart
 create mode 100644 frontend/app/lib/pb/payment.pbserver.dart
 create mode 100644 frontend/app/lib/pb/person.pb.dart
 create mode 100644 frontend/app/lib/pb/person.pbenum.dart
 create mode 100644 frontend/app/lib/pb/person.pbjson.dart
 create mode 100644 frontend/app/lib/pb/person.pbserver.dart
 create mode 100644 frontend/app/lib/pb/returns_log.pb.dart
 create mode 100644 frontend/app/lib/pb/returns_log.pbenum.dart
 create mode 100644 frontend/app/lib/pb/returns_log.pbjson.dart
 create mode 100644 frontend/app/lib/pb/returns_log.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_block_session.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_block_session.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_block_session.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_block_session.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_create_account.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_create_account.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_create_account.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_create_account.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_create_account_info.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_create_account_info.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_create_account_info.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_create_account_info.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_create_payment.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_create_payment.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_create_payment.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_create_payment.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_create_person.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_create_person.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_create_person.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_create_person.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_delete_document.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_delete_document.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_delete_document.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_delete_document.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_delete_payment.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_delete_payment.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_delete_payment.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_delete_payment.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_delete_person.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_delete_person.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_delete_person.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_delete_person.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_get_account.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_get_account.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_get_account.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_get_account.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_get_account_info.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_get_account_info.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_get_account_info.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_get_account_info.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_get_payment.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_get_payment.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_get_payment.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_get_payment.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_get_person.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_get_person.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_get_person.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_get_person.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_account_info.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_account_info.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_account_info.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_account_info.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_accounts.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_accounts.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_accounts.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_accounts.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_payments.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_payments.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_payments.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_payments.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_persons.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_persons.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_persons.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_persons.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_sessions.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_sessions.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_sessions.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_list_sessions.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_login.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_login.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_login.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_login.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_refresh_token.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_refresh_token.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_refresh_token.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_refresh_token.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_account.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_account.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_account.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_account.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_account_info.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_account_info.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_account_info.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_account_info.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_account_privacy.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_account_privacy.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_account_privacy.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_account_privacy.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_payment.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_payment.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_payment.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_payment.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_person.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_person.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_person.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_update_person.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_upload_document.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_upload_document.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_upload_document.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_upload_document.pbserver.dart
 create mode 100644 frontend/app/lib/pb/rpc_verify_email.pb.dart
 create mode 100644 frontend/app/lib/pb/rpc_verify_email.pbenum.dart
 create mode 100644 frontend/app/lib/pb/rpc_verify_email.pbjson.dart
 create mode 100644 frontend/app/lib/pb/rpc_verify_email.pbserver.dart
 create mode 100644 frontend/app/lib/pb/service_df.pb.dart
 create mode 100644 frontend/app/lib/pb/service_df.pbenum.dart
 create mode 100644 frontend/app/lib/pb/service_df.pbjson.dart
 create mode 100644 frontend/app/lib/pb/service_df.pbserver.dart
 create mode 100644 frontend/app/lib/pb/session.pb.dart
 create mode 100644 frontend/app/lib/pb/session.pbenum.dart
 create mode 100644 frontend/app/lib/pb/session.pbjson.dart
 create mode 100644 frontend/app/lib/pb/session.pbserver.dart
 create mode 100644 frontend/app/linux/.gitignore
 create mode 100644 frontend/app/linux/CMakeLists.txt
 create mode 100644 frontend/app/linux/flutter/CMakeLists.txt
 create mode 100644 frontend/app/linux/flutter/generated_plugin_registrant.cc
 create mode 100644 frontend/app/linux/flutter/generated_plugin_registrant.h
 create mode 100644 frontend/app/linux/flutter/generated_plugins.cmake
 create mode 100644 frontend/app/linux/main.cc
 create mode 100644 frontend/app/linux/my_application.cc
 create mode 100644 frontend/app/linux/my_application.h
 create mode 100644 frontend/app/macos/.gitignore
 create mode 100644 frontend/app/macos/Flutter/Flutter-Debug.xcconfig
 create mode 100644 frontend/app/macos/Flutter/Flutter-Release.xcconfig
 create mode 100644 frontend/app/macos/Runner.xcodeproj/project.pbxproj
 create mode 100644 frontend/app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
 create mode 100644 frontend/app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
 create mode 100644 frontend/app/macos/Runner.xcworkspace/contents.xcworkspacedata
 create mode 100644 frontend/app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
 create mode 100644 frontend/app/macos/Runner/AppDelegate.swift
 create mode 100644 frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
 create mode 100644 frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
 create mode 100644 frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
 create mode 100644 frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
 create mode 100644 frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
 create mode 100644 frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
 create mode 100644 frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
 create mode 100644 frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
 create mode 100644 frontend/app/macos/Runner/Base.lproj/MainMenu.xib
 create mode 100644 frontend/app/macos/Runner/Configs/AppInfo.xcconfig
 create mode 100644 frontend/app/macos/Runner/Configs/Debug.xcconfig
 create mode 100644 frontend/app/macos/Runner/Configs/Release.xcconfig
 create mode 100644 frontend/app/macos/Runner/Configs/Warnings.xcconfig
 create mode 100644 frontend/app/macos/Runner/DebugProfile.entitlements
 create mode 100644 frontend/app/macos/Runner/Info.plist
 create mode 100644 frontend/app/macos/Runner/MainFlutterWindow.swift
 create mode 100644 frontend/app/macos/Runner/Release.entitlements
 create mode 100644 frontend/app/macos/RunnerTests/RunnerTests.swift
 create mode 100644 frontend/app/pubspec.lock
 create mode 100644 frontend/app/pubspec.yaml
 create mode 100644 frontend/app/web/favicon.png
 create mode 100644 frontend/app/web/icons/Icon-192.png
 create mode 100644 frontend/app/web/icons/Icon-512.png
 create mode 100644 frontend/app/web/icons/Icon-maskable-192.png
 create mode 100644 frontend/app/web/icons/Icon-maskable-512.png
 create mode 100644 frontend/app/web/index.html
 create mode 100644 frontend/app/web/manifest.json
 create mode 100644 frontend/app/windows/.gitignore
 create mode 100644 frontend/app/windows/CMakeLists.txt
 create mode 100644 frontend/app/windows/flutter/CMakeLists.txt
 create mode 100644 frontend/app/windows/flutter/generated_plugin_registrant.cc
 create mode 100644 frontend/app/windows/flutter/generated_plugin_registrant.h
 create mode 100644 frontend/app/windows/flutter/generated_plugins.cmake
 create mode 100644 frontend/app/windows/runner/CMakeLists.txt
 create mode 100644 frontend/app/windows/runner/Runner.rc
 create mode 100644 frontend/app/windows/runner/flutter_window.cpp
 create mode 100644 frontend/app/windows/runner/flutter_window.h
 create mode 100644 frontend/app/windows/runner/main.cpp
 create mode 100644 frontend/app/windows/runner/resource.h
 create mode 100644 frontend/app/windows/runner/resources/app_icon.ico
 create mode 100644 frontend/app/windows/runner/runner.exe.manifest
 create mode 100644 frontend/app/windows/runner/utils.cpp
 create mode 100644 frontend/app/windows/runner/utils.h
 create mode 100644 frontend/app/windows/runner/win32_window.cpp
 create mode 100644 frontend/app/windows/runner/win32_window.h

diff --git a/Makefile b/Makefile
index 6efea5a..48c328f 100644
--- a/Makefile
+++ b/Makefile
@@ -96,6 +96,12 @@ proto:
 	./proto/*.proto
 	cd ..
 
+proto_app:
+	cd frontend/app && \
+	rm -f lib/pb/*.dart && \
+	protoc -I=../../bff/proto --dart_out=lib/pb ../../bff/proto/*.proto
+	cd ../..
+
 evans:
 	evans --host localhost --port 9090 --package pb -r repl
 
diff --git a/frontend/app/.gitignore b/frontend/app/.gitignore
new file mode 100644
index 0000000..7c46a55
--- /dev/null
+++ b/frontend/app/.gitignore
@@ -0,0 +1,861 @@
+# Miscellaneous
+*.class
+#*.lock
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# Visual Studio Code related
+.classpath
+.project
+.settings/
+.vscode/
+
+# Flutter repo-specific
+/bin/cache/
+/bin/internal/bootstrap.bat
+/bin/internal/bootstrap.sh
+/bin/mingit/
+/dev/benchmarks/mega_gallery/
+/dev/bots/.recipe_deps
+/dev/bots/android_tools/
+/dev/devicelab/ABresults*.json
+/dev/docs/doc/
+/dev/docs/flutter.docs.zip
+/dev/docs/lib/
+/dev/docs/pubspec.yaml
+/dev/integration_tests/**/xcuserdata
+/dev/integration_tests/**/Pods
+/packages/flutter/coverage/
+version
+analysis_benchmark.json
+
+# packages file containing multi-root paths
+.packages.generated
+
+# Flutter/Dart/Pub related
+**/doc/api/
+.dart_tool/
+.flutter-plugins
+.flutter-plugins-dependencies
+**/generated_plugin_registrant.dart
+.packages
+.pub-cache/
+.pub/
+build/
+flutter_*.png
+linked_*.ds
+unlinked.ds
+unlinked_spec.ds
+
+# Android related
+**/android/**/gradle-wrapper.jar
+.gradle/
+**/android/captures/
+**/android/gradlew
+**/android/gradlew.bat
+**/android/local.properties
+**/android/**/GeneratedPluginRegistrant.java
+**/android/key.properties
+# *.jks
+
+# iOS/XCode related
+**/ios/**/*.mode1v3
+**/ios/**/*.mode2v3
+**/ios/**/*.moved-aside
+**/ios/**/*.pbxuser
+**/ios/**/*.perspectivev3
+**/ios/**/*sync/
+**/ios/**/.sconsign.dblite
+**/ios/**/.tags*
+**/ios/**/.vagrant/
+**/ios/**/DerivedData/
+**/ios/**/Icon?
+**/ios/**/Pods/
+**/ios/**/.symlinks/
+**/ios/**/profile
+**/ios/**/xcuserdata
+**/ios/.generated/
+**/ios/Flutter/.last_build_id
+**/ios/Flutter/App.framework
+**/ios/Flutter/Flutter.framework
+**/ios/Flutter/Flutter.podspec
+**/ios/Flutter/Generated.xcconfig
+**/ios/Flutter/ephemeral
+**/ios/Flutter/app.flx
+**/ios/Flutter/app.zip
+**/ios/Flutter/flutter_assets/
+**/ios/Flutter/flutter_export_environment.sh
+**/ios/ServiceDefinitions.json
+**/ios/Runner/GeneratedPluginRegistrant.*
+
+# macOS
+**/macos/Flutter/GeneratedPluginRegistrant.swift
+
+# Coverage
+coverage/
+
+# Symbols
+app.*.symbols
+
+# Exceptions to above rules.
+!**/ios/**/default.mode1v3
+!**/ios/**/default.mode2v3
+!**/ios/**/default.pbxuser
+!**/ios/**/default.perspectivev3
+!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
+!/dev/ci/**/Gemfile.lock
+
+
+## Related .gitignores ##
+
+# Firebase configuration files / Google Services (e.g. APIs or Firebase)
+ios/Runner/GoogleService-Info.plist
+android/app/google-services.json
+
+# Google Maps API
+google_maps_api.xml
+
+# Web related
+lib/generated_plugin_registrant.dart
+
+# Obfuscation related
+app.*.map.json
+
+
+### --------------------------- Dart.gitignore ------------------------- ###
+
+# See https://www.dartlang.org/guides/libraries/private-files
+
+# Files and directories created by pub
+#.dart_tool/
+#.packages
+#build/
+# If you're building an application, you may want to check-in your pubspec.lock
+#pubspec.lock
+
+# Directory created by dartdoc
+# If you don't generate documentation locally you can remove this line.
+doc/api/
+
+# dotenv environment variables file
+.env*
+
+# Avoid committing generated Javascript files:
+*.dart.js
+*.info.json      # Produced by the --dump-info flag.
+*.js             # When generated by dart2js. Don't specify *.js if your
+                 # project includes source files written in JavaScript.
+*.js_
+*.js.deps
+*.js.map
+
+#.flutter-plugins
+#.flutter-plugins-dependencies
+
+
+### -------------------------- Swift.gitignore  ------------------------ ###
+
+# Xcode
+#
+# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
+
+## User settings
+#xcuserdata/
+
+## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
+#*.xcscmblueprint
+#*.xccheckout
+
+## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
+#build/
+#DerivedData/
+#*.moved-aside
+#*.pbxuser
+#!default.pbxuser
+#*.mode1v3
+#!default.mode1v3
+#*.mode2v3
+#!default.mode2v3
+#*.perspectivev3
+#!default.perspectivev3
+
+## Obj-C/Swift specific
+*.hmap
+
+## App packaging
+*.ipa
+*.dSYM.zip
+*.dSYM
+
+## Playgrounds
+timeline.xctimeline
+playground.xcworkspace
+
+# Swift Package Manager
+
+# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
+ Packages/
+ Package.pins
+ Package.resolved
+ *.xcodeproj
+
+# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
+# hence it is not needed unless you have added a package configuration file to your project
+ .swiftpm
+
+.build/
+
+# CocoaPods
+#
+# We recommend against adding the Pods directory to your .gitignore. However
+# you should judge for yourself, the pros and cons are mentioned at:
+# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
+#
+# Pods/
+#
+# Add this line if you want to avoid checking in source code from the Xcode workspace
+# *.xcworkspace
+
+# Carthage
+#
+# Add this line if you want to avoid checking in source code from Carthage dependencies.
+# Carthage/Checkouts
+
+Carthage/Build/
+
+# Accio dependency management
+Dependencies/
+.accio/
+
+# fastlane
+#
+# It is recommended to not store the screenshots in the git repo.
+# Instead, use fastlane to re-generate the screenshots whenever they are needed.
+# For more information about the recommended setup visit:
+# https://docs.fastlane.tools/best-practices/source-control/#source-control
+
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots/**/*.png
+fastlane/test_output
+
+# Code Injection
+#
+# After new code Injection tools there's a generated folder /iOSInjectionProject
+# https://github.com/johnno1962/injectionforxcode
+
+iOSInjectionProject/
+
+
+### -------------------------- Java.gitignore -------------------------- ###
+
+# Compiled class file
+#*.class
+
+# Log file
+#*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+#*.jar
+*.war
+*.nar
+*.ear
+#*.zip
+*.tar.gz
+#*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+replay_pid*
+
+
+### -------------------------- Kotlin.gitignore ------------------------ ###
+
+#.DS_Store
+.idea/shelf
+/confluence/target
+/dependencies/repo
+/android.tests.dependencies
+/dependencies/android.tests.dependencies
+/dist
+/local
+/gh-pages
+/ideaSDK
+/clionSDK
+/android-studio/sdk
+#out/
+/tmp
+/intellij
+workspace.xml
+*.versionsBackup
+/idea/testData/debugger/tinyApp/classes*
+/jps-plugin/testData/kannotator
+/js/js.translator/testData/out/
+/js/js.translator/testData/out-min/
+/js/js.translator/testData/out-pir/
+#.gradle/
+#build/
+!**/src/**/build
+!**/test/**/build
+#*.iml
+!**/testData/**/*.iml
+.idea/remote-targets.xml
+.idea/libraries/Gradle*.xml
+.idea/libraries/Maven*.xml
+.idea/artifacts/PILL_*.xml
+.idea/artifacts/KotlinPlugin.xml
+#.idea/modules
+.idea/runConfigurations/JPS_*.xml
+.idea/runConfigurations/PILL_*.xml
+.idea/runConfigurations/_FP_*.xml
+.idea/runConfigurations/_MT_*.xml
+#.idea/libraries
+#.idea/modules.xml
+#.idea/gradle.xml
+#.idea/compiler.xml
+.idea/inspectionProfiles/profiles_settings.xml
+.idea/.name
+.idea/artifacts/dist_auto_*
+.idea/artifacts/dist.xml
+.idea/artifacts/ideaPlugin.xml
+.idea/artifacts/kotlinc.xml
+.idea/artifacts/kotlin_compiler_jar.xml
+.idea/artifacts/kotlin_plugin_jar.xml
+.idea/artifacts/kotlin_jps_plugin_jar.xml
+.idea/artifacts/kotlin_daemon_client_jar.xml
+.idea/artifacts/kotlin_imports_dumper_compiler_plugin_jar.xml
+.idea/artifacts/kotlin_main_kts_jar.xml
+.idea/artifacts/kotlin_compiler_client_embeddable_jar.xml
+.idea/artifacts/kotlin_reflect_jar.xml
+.idea/artifacts/kotlin_stdlib_js_ir_*
+.idea/artifacts/kotlin_test_js_ir_*
+.idea/artifacts/kotlin_stdlib_wasm_*
+.idea/artifacts/kotlinx_atomicfu_runtime_*
+#.idea/jarRepositories.xml
+.idea/csv-plugin.xml
+.idea/libraries-with-intellij-classes.xml
+.idea/misc.xml
+node_modules/
+.rpt2_cache/
+libraries/tools/kotlin-test-js-runner/lib/
+#local.properties
+buildSrcTmp/
+distTmp/
+outTmp/
+/test.output
+/kotlin-native/dist
+kotlin-ide/
+
+
+### ------------------------- Android.gitignore ------------------------ ###
+
+# Built application files
+*.apk
+*.ap_
+
+# Files for the ART/Dalvik VM
+*.dex
+
+# Generated files
+bin/
+gen/
+out/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# IntelliJ
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/gradle.xml
+.idea/assetWizardSettings.xml
+.idea/dictionaries
+.idea/libraries
+.idea/caches
+
+# External native build folder generated in Android Studio 2.2 and later
+.externalNativeBuild
+
+# Freeline
+freeline.py
+freeline/
+freeline_project_description.json
+
+# fastlane
+#fastlane/report.xml
+#fastlane/Preview.html
+fastlane/screenshots
+#fastlane/test_output
+fastlane/readme.md
+
+# Keystore files
+*.jks
+*.keystore
+
+
+### ------------------------- Gradle.gitignore ------------------------- ###
+
+.gradle
+**/build/
+!src/**/build/
+
+# Ignore Gradle GUI config
+gradle-app.setting
+
+# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
+!gradle-wrapper.jar
+
+# Cache of project
+.gradletasknamecache
+
+# Eclipse Gradle plugin generated files
+# Eclipse Core
+#.project
+# JDT-specific (Eclipse Java Development Tools)
+#.classpath
+
+
+### ------------------------- Maven.gitignore -------------------------- ###
+
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+# https://github.com/takari/maven-wrapper#usage-without-binary-jar
+.mvn/wrapper/maven-wrapper.jar
+
+# Eclipse m2e generated files
+# Eclipse Core
+#.project
+# JDT-specific (Eclipse Java Development Tools)
+#.classpath
+
+
+### ------------------------ JetBrains.gitignore ----------------------- ###
+
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# AWS User-specific
+.idea/**/aws.xml
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn.  Uncomment if using
+# auto-import.
+ .idea/artifacts
+ .idea/compiler.xml
+ .idea/jarRepositories.xml
+ .idea/modules.xml
+ .idea/*.iml
+ .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+#*.iws
+
+# IntelliJ
+#out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# SonarLint plugin
+.idea/sonarlint/
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+
+### ------------------------- Xcode.gitignore -------------------------- ###
+
+# Xcode
+#
+# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
+
+## User settings
+xcuserdata/
+
+## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
+*.xcscmblueprint
+*.xccheckout
+
+## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
+#build/
+DerivedData/
+*.moved-aside
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+
+## Gcc Patch
+/*.gcno
+
+
+### -------------------- VisualStudioCode.gitignore  ------------------- ###
+
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+!.vscode/*.code-snippets
+
+# Local History for Visual Studio Code
+.history/
+
+# Built Visual Studio Code Extensions
+*.vsix
+
+
+### ----------------------- SublimeText.gitignore ---------------------- ###
+
+# Cache files for Sublime Text
+*.tmlanguage.cache
+*.tmPreferences.cache
+*.stTheme.cache
+
+# Workspace files are user-specific
+*.sublime-workspace
+
+# Project files should be checked into the repository, unless a significant
+# proportion of contributors will probably not be using Sublime Text
+# *.sublime-project
+
+# SFTP configuration file
+sftp-config.json
+sftp-config-alt*.json
+
+# Package control specific files
+Package Control.last-run
+Package Control.ca-list
+Package Control.ca-bundle
+Package Control.system-ca-bundle
+Package Control.cache/
+Package Control.ca-certs/
+Package Control.merged-ca-bundle
+Package Control.user-ca-bundle
+oscrypto-ca-bundle.crt
+bh_unicode_properties.cache
+
+# Sublime-github package stores a github token in this file
+# https://packagecontrol.io/packages/sublime-github
+GitHub.sublime-settings
+
+
+### -------------------------- Emacs.gitignore ------------------------- ###
+
+# -*- mode: gitignore; -*-
+#*~
+\#*\#
+/.emacs.desktop
+/.emacs.desktop.lock
+*.elc
+auto-save-list
+tramp
+.\#*
+
+# Org-mode
+.org-id-locations
+*_archive
+
+# flymake-mode
+*_flymake.*
+
+# eshell files
+/eshell/history
+/eshell/lastdir
+
+# elpa packages
+/elpa/
+
+# reftex files
+*.rel
+
+# AUCTeX auto folder
+/auto/
+
+# cask packages
+.cask/
+dist/
+
+# Flycheck
+flycheck_*.el
+
+# server auth directory
+/server/
+
+# projectiles files
+.projectile
+
+# directory configuration
+.dir-locals.el
+
+# network security
+/network-security.data
+
+
+### -------------------------- Vim.gitignore  -------------------------- ###
+
+# Swap
+[._]*.s[a-v][a-z]
+!*.svg  # comment out if you don't need vector files
+[._]*.sw[a-p]
+[._]s[a-rt-v][a-z]
+[._]ss[a-gi-z]
+[._]sw[a-p]
+
+# Session
+Session.vim
+Sessionx.vim
+
+# Temporary
+.netrwhist
+#*~
+# Auto-generated tag files
+tags
+# Persistent undo
+[._]*.un~
+
+
+### ------------------------ Windows.gitignore  ------------------------ ###
+
+# Windows thumbnail cache files
+Thumbs.db
+Thumbs.db:encryptable
+ehthumbs.db
+ehthumbs_vista.db
+
+# Dump file
+*.stackdump
+
+# Folder config file
+[Dd]esktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+
+### ------------------------- macOS.gitignore -------------------------- ###
+
+# General
+#.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+
+### -------------------------- Linux.gitignore ------------------------- ###
+
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+# .nfs files are created when an open file is removed but is still being accessed
+.nfs*
+
+
+### ------------------------ Archives.gitignore ------------------------ ###
+
+# It's better to unpack these files and commit the raw source because
+# git has its own built in compression methods.
+*.7z
+*.jar
+*.rar
+*.zip
+*.gz
+*.gzip
+*.tgz
+*.bzip
+*.bzip2
+*.bz2
+*.xz
+*.lzma
+#*.cab
+*.xar
+
+# Packing-only formats
+*.iso
+*.tar
+
+# Package management formats
+*.dmg
+*.xpi
+*.gem
+*.egg
+*.deb
+*.rpm
+#*.msi
+#*.msm
+#*.msp
+*.txz
+
+
+### ------------------------- Backup.gitignore ------------------------- ###
+
+*.bak
+*.gho
+*.ori
+*.orig
+*.tmp
+
+
+### -------------------------- JEnv.gitignore -------------------------- ###
+
+# JEnv local Java version configuration file
+.java-version
+
+# Used by previous versions of JEnv
+.jenv-version
+
+
+### ------------------------- Project Specific ------------------------- ###
+
+# Include any specific files here.
+
+
+### ---------------------------- References ---------------------------- ###
+
+# Flutter          - https://github.com/flutter/flutter/blob/master/.gitignore
+# Dart             - https://github.com/github/gitignore/blob/main/Dart.gitignore
+# Swift            - https://github.com/github/gitignore/blob/main/Swift.gitignore
+# Java             - https://github.com/github/gitignore/blob/main/Java.gitignore
+# Kotlin           - https://github.com/JetBrains/kotlin/blob/master/.gitignore
+# Android          - https://github.com/github/gitignore/blob/main/Android.gitignore
+# Gradle           - https://github.com/github/gitignore/blob/main/Gradle.gitignore
+# Maven            - https://github.com/github/gitignore/blob/main/Maven.gitignore
+
+# JetBrains        - https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+# Xcode            - https://github.com/github/gitignore/blob/main/Global/Xcode.gitignore
+# VisualStudioCode - https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
+# SublimeText      - https://github.com/github/gitignore/blob/main/Global/SublimeText.gitignore
+# Emacs            - https://github.com/github/gitignore/blob/main/Global/Emacs.gitignore
+# Vim              - https://github.com/github/gitignore/blob/main/Global/Vim.gitignore
+
+# Windows          - https://github.com/github/gitignore/blob/main/Global/Windows.gitignore
+# macOS            - https://github.com/github/gitignore/blob/main/Global/macOS.gitignore
+# Linux            - https://github.com/github/gitignore/blob/main/Global/Linux.gitignore
+
+# Archives         - https://github.com/github/gitignore/blob/main/Global/Archives.gitignore
+# Backup           - https://github.com/github/gitignore/blob/main/Global/Backup.gitignore
+# JEnv             - https://github.com/github/gitignore/blob/main/Global/JEnv.gitignore
\ No newline at end of file
diff --git a/frontend/app/.metadata b/frontend/app/.metadata
new file mode 100644
index 0000000..acfc1cf
--- /dev/null
+++ b/frontend/app/.metadata
@@ -0,0 +1,45 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+  revision: "6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e"
+  channel: "stable"
+
+project_type: app
+
+# Tracks metadata for the flutter migrate command
+migration:
+  platforms:
+    - platform: root
+      create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
+      base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
+    - platform: android
+      create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
+      base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
+    - platform: ios
+      create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
+      base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
+    - platform: linux
+      create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
+      base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
+    - platform: macos
+      create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
+      base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
+    - platform: web
+      create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
+      base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
+    - platform: windows
+      create_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
+      base_revision: 6c4930c4ac86fb286f30e31d0ec8bffbcbb9953e
+
+  # User provided section
+
+  # List of Local paths (relative to this file) that should be
+  # ignored by the migrate tool.
+  #
+  # Files that are not part of the templates will be ignored by default.
+  unmanaged_files:
+    - 'lib/main.dart'
+    - 'ios/Runner.xcodeproj/project.pbxproj'
diff --git a/frontend/app/README.md b/frontend/app/README.md
new file mode 100644
index 0000000..b73cfb0
--- /dev/null
+++ b/frontend/app/README.md
@@ -0,0 +1,16 @@
+# app
+
+A new Flutter project.
+
+## Getting Started
+
+This project is a starting point for a Flutter application.
+
+A few resources to get you started if this is your first Flutter project:
+
+- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
+- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
+
+For help getting started with Flutter development, view the
+[online documentation](https://docs.flutter.dev/), which offers tutorials,
+samples, guidance on mobile development, and a full API reference.
diff --git a/frontend/app/analysis_options.yaml b/frontend/app/analysis_options.yaml
new file mode 100644
index 0000000..0d29021
--- /dev/null
+++ b/frontend/app/analysis_options.yaml
@@ -0,0 +1,28 @@
+# This file configures the analyzer, which statically analyzes Dart code to
+# check for errors, warnings, and lints.
+#
+# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
+# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
+# invoked from the command line by running `flutter analyze`.
+
+# The following line activates a set of recommended lints for Flutter apps,
+# packages, and plugins designed to encourage good coding practices.
+include: package:flutter_lints/flutter.yaml
+
+linter:
+  # The lint rules applied to this project can be customized in the
+  # section below to disable rules from the `package:flutter_lints/flutter.yaml`
+  # included above or to enable additional rules. A list of all available lints
+  # and their documentation is published at https://dart.dev/lints.
+  #
+  # Instead of disabling a lint rule for the entire project in the
+  # section below, it can also be suppressed for a single line of code
+  # or a specific dart file by using the `// ignore: name_of_lint` and
+  # `// ignore_for_file: name_of_lint` syntax on the line or in the file
+  # producing the lint.
+  rules:
+    # avoid_print: false  # Uncomment to disable the `avoid_print` rule
+    # prefer_single_quotes: true  # Uncomment to enable the `prefer_single_quotes` rule
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options
diff --git a/frontend/app/android/.gitignore b/frontend/app/android/.gitignore
new file mode 100644
index 0000000..6f56801
--- /dev/null
+++ b/frontend/app/android/.gitignore
@@ -0,0 +1,13 @@
+gradle-wrapper.jar
+/.gradle
+/captures/
+/gradlew
+/gradlew.bat
+/local.properties
+GeneratedPluginRegistrant.java
+
+# Remember to never publicly share your keystore.
+# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
+key.properties
+**/*.keystore
+**/*.jks
diff --git a/frontend/app/android/app/build.gradle b/frontend/app/android/app/build.gradle
new file mode 100644
index 0000000..d6f6037
--- /dev/null
+++ b/frontend/app/android/app/build.gradle
@@ -0,0 +1,67 @@
+plugins {
+    id "com.android.application"
+    id "kotlin-android"
+    id "dev.flutter.flutter-gradle-plugin"
+}
+
+def localProperties = new Properties()
+def localPropertiesFile = rootProject.file('local.properties')
+if (localPropertiesFile.exists()) {
+    localPropertiesFile.withReader('UTF-8') { reader ->
+        localProperties.load(reader)
+    }
+}
+
+def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
+if (flutterVersionCode == null) {
+    flutterVersionCode = '1'
+}
+
+def flutterVersionName = localProperties.getProperty('flutter.versionName')
+if (flutterVersionName == null) {
+    flutterVersionName = '1.0'
+}
+
+android {
+    namespace "com.example.app"
+    compileSdkVersion flutter.compileSdkVersion
+    ndkVersion flutter.ndkVersion
+
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+
+    kotlinOptions {
+        jvmTarget = '1.8'
+    }
+
+    sourceSets {
+        main.java.srcDirs += 'src/main/kotlin'
+    }
+
+    defaultConfig {
+        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
+        applicationId "com.example.app"
+        // You can update the following values to match your application needs.
+        // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
+        minSdkVersion flutter.minSdkVersion
+        targetSdkVersion flutter.targetSdkVersion
+        versionCode flutterVersionCode.toInteger()
+        versionName flutterVersionName
+    }
+
+    buildTypes {
+        release {
+            // TODO: Add your own signing config for the release build.
+            // Signing with the debug keys for now, so `flutter run --release` works.
+            signingConfig signingConfigs.debug
+        }
+    }
+}
+
+flutter {
+    source '../..'
+}
+
+dependencies {}
diff --git a/frontend/app/android/app/src/debug/AndroidManifest.xml b/frontend/app/android/app/src/debug/AndroidManifest.xml
new file mode 100644
index 0000000..399f698
--- /dev/null
+++ b/frontend/app/android/app/src/debug/AndroidManifest.xml
@@ -0,0 +1,7 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- The INTERNET permission is required for development. Specifically,
+         the Flutter tool needs it to communicate with the running application
+         to allow setting breakpoints, to provide hot reload, etc.
+    -->
+    <uses-permission android:name="android.permission.INTERNET"/>
+</manifest>
diff --git a/frontend/app/android/app/src/main/AndroidManifest.xml b/frontend/app/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..e8847cc
--- /dev/null
+++ b/frontend/app/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,33 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+    <application
+        android:label="app"
+        android:name="${applicationName}"
+        android:icon="@mipmap/ic_launcher">
+        <activity
+            android:name=".MainActivity"
+            android:exported="true"
+            android:launchMode="singleTop"
+            android:theme="@style/LaunchTheme"
+            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
+            android:hardwareAccelerated="true"
+            android:windowSoftInputMode="adjustResize">
+            <!-- Specifies an Android theme to apply to this Activity as soon as
+                 the Android process has started. This theme is visible to the user
+                 while the Flutter UI initializes. After that, this theme continues
+                 to determine the Window background behind the Flutter UI. -->
+            <meta-data
+              android:name="io.flutter.embedding.android.NormalTheme"
+              android:resource="@style/NormalTheme"
+              />
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+        <!-- Don't delete the meta-data below.
+             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
+        <meta-data
+            android:name="flutterEmbedding"
+            android:value="2" />
+    </application>
+</manifest>
diff --git a/frontend/app/android/app/src/main/kotlin/com/example/app/MainActivity.kt b/frontend/app/android/app/src/main/kotlin/com/example/app/MainActivity.kt
new file mode 100644
index 0000000..461fcfb
--- /dev/null
+++ b/frontend/app/android/app/src/main/kotlin/com/example/app/MainActivity.kt
@@ -0,0 +1,6 @@
+package com.example.app
+
+import io.flutter.embedding.android.FlutterActivity
+
+class MainActivity: FlutterActivity() {
+}
diff --git a/frontend/app/android/app/src/main/res/drawable-v21/launch_background.xml b/frontend/app/android/app/src/main/res/drawable-v21/launch_background.xml
new file mode 100644
index 0000000..f74085f
--- /dev/null
+++ b/frontend/app/android/app/src/main/res/drawable-v21/launch_background.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Modify this file to customize your launch splash screen -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="?android:colorBackground" />
+
+    <!-- You can insert your own image assets here -->
+    <!-- <item>
+        <bitmap
+            android:gravity="center"
+            android:src="@mipmap/launch_image" />
+    </item> -->
+</layer-list>
diff --git a/frontend/app/android/app/src/main/res/drawable/launch_background.xml b/frontend/app/android/app/src/main/res/drawable/launch_background.xml
new file mode 100644
index 0000000..304732f
--- /dev/null
+++ b/frontend/app/android/app/src/main/res/drawable/launch_background.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Modify this file to customize your launch splash screen -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@android:color/white" />
+
+    <!-- You can insert your own image assets here -->
+    <!-- <item>
+        <bitmap
+            android:gravity="center"
+            android:src="@mipmap/launch_image" />
+    </item> -->
+</layer-list>
diff --git a/frontend/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/frontend/app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..db77bb4b7b0906d62b1847e87f15cdcacf6a4f29
GIT binary patch
literal 544
zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAj~WQl7;NpOBzNqJ&XDuZK6ep0G}
zXKrG8YEWuoN@d~6R2!h8bpbvhu0Wd6uZuB!w&u2PAxD2eNXD>P5D~Wn-+_Wa#27Xc
zC?Zj|6r#X(-D3u$NCt}(Ms06KgJ4FxJVv{GM)!I~&n8Bnc94O7-Hd)cjDZswgC;Qs
zO=b+9!WcT8F?0rF7!Uys2bs@gozCP?z~o%U<k`UN+s5qQ#T?KrmN7v*f2L%`GO4-^
z(#_kX+jhyc?*UrsvLED<w+p3gfi4y<3GxeO5CDRJfCLa|I1d8%B?X@R0!qL1ba4!c
zIQ;g^b-pGC0f)elH+vJ_clF3>|N3vA*22N<t#oc3|FNCx%`Ll}Jbl*Q`}yg~1ZO@=
zF!6p)NTYsh!6(JdtLiRuwi@`&XeqAXe9fY|=kfFy_3t|md##(iHE+K4ydxH3>aGQG
zlg@K`O_XuxvZ&Ks^m&R!`&1=spLvfx7oGDKDwpwW`#i<K@6w~yiZZH!59hqLTYF-H
zp0%uz(2~z(X$>qdw@AL`7MR}m`rwr|mZgU`8P7SB<Kba6`>kL78fFf!WnuYWm$5Z0
zNXhDbCv&49sM544K|?c)WrFfiZ<W8RzO1)p=v7f>vCi9h0O)B3Pgg&ebxsLQ05GG~
AQ2+n{

literal 0
HcmV?d00001

diff --git a/frontend/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/frontend/app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..17987b79bb8a35cc66c3c1fd44f5a5526c1b78be
GIT binary patch
literal 442
zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*D5Xx&nMcT!A!W`0S9QKQy;}1Cl^CgaH=;G9cpY;r$Q>i*pfB
zP2drbID<_#qf;rPZx^FqH)F_D#*k@@q0<?|W-^A&VhjhO+044$%!YxiPI;`p4Q#=k
za-F;6dk-j1J*_nBlG2>3KywUtLX8Ua?`H+NMzkczFPK3<KtaL4z@UHr{Pp|KpFjT|
z1oAia3j-A_^>lFz@i_kW%1NOn0|D2I9n9wzH8m|-tHjsw|9>@K=iMBhxvkv6m8Y-l
zyt<ns@%x_-ezPmiS-=02Ut8`WUGa5ad?jb?UB<rkVmAJ)*Xy}nR&U>Q?X=U+MF$@3
zt`~i=@j|6y)RWMK--}M|=T`o&^Ni>IoWKHEbBXz7?A@mgWoL>!*SXo`SZH-*HSdS+
yn*9;$7;m`l>wYBC5bq;=U}IMqLzqbYCidGC!)_gkIk_C@U<OZDKbLh*2~7avPrJzg

literal 0
HcmV?d00001

diff --git a/frontend/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/frontend/app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..09d4391482be68e9e4a07fab769b5de337d16eb1
GIT binary patch
literal 721
zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD3?#3*wSy!iOI#yLg7ec#$`gxH85~pclTsBt
za}(23gHjVyDhp4h+5i=O3-AeX1=1l$e`s#|#^}+&7(N@w0CIr{$Oe+Uk^K-ZP~83C
zcc@hG6rikF&NPT(23>y!y&wkt5C($~2D>~)O*cj@FGjOCM)M>_ixfudOh)?xMu#Fs
z#}Y=@YDTwOM)x{K_j*Q;dPdJ?Mz0n|pLRx{4n|)f>SXlmV)XB04CrSJn#dS5nK2lM
zrZ9#~WelCp7&e13Y$jvaEXHskn$2V!!DN-nWS__6T*l;H&Fopn?A6HZ-6WRLFP=R`
zqG+CE#d4|IbyAI+rJJ`&x9*T`+a=p|0O(+s{UBcyZdkhj=yS1>AirP+0R;mf2uMgM
zC}@~JfByORAh4SyRgi&!(cja>F(l*O+nd+@4m$|6K6KDn_&uvCpV23&>G9HJp{xgg
z<JnHTOuK%sGbNji)8cv6*ZNtnbwxJZ-?eY1e-ZPG#r<}_kct2Ie>oq1^2_p9@|WEo
z*X_Uko@K)qYYv~<poG`LOv(2(Hhkk{Dz;b6_#4<(=XBwh@>>43eQGMdbiGbo>E~Q&
zr<n4_y=h^-h|%}kO&jwCioQ5EzF6K8^VdP)H>YBH{QP^@Sti!`2)uG{irBBq@y*$B
zi#&(U-*=fp74j)RyIw49+0MRPMRU)+a2r*PJ$L5roHt2$UjExCTZSbq%V!HeS7J$N
zdG@vOZB4v_lF7Plrx+hxo7(fCV&}f<lyK#S=nvDw%*y%vwN3psIS+1s7G}QfbZGd|
zV;VoMy*YI2-%hU{-w$hl9!*Y_m~60h&vVVs6)lfgu09v4QWIt25UBGxaN`?mVmn*e
U?z!!Jz`$qlboFyt=akR{0C)T?>Hq)$

literal 0
HcmV?d00001

diff --git a/frontend/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/frontend/app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..d5f1c8d34e7a88e3f88bea192c3a370d44689c3c
GIT binary patch
literal 1031
zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=BuiW)N`mv#O3D+9QW+dm@{>{(
zJaZG%Q-e|yQz{EjrrIztFa`(sgt!6~Yi|1%a`XoT0ojZ}lNrNjb9xj&#3c(B0U1_%
zz5^97Xt*<I`!eYGGw1~|=m#_ChcFm~F&M`%SZ6TU=QA3HGn&RTnk6urCox*3Gg@ad
z+GI1@<S^O-Q7)rh9;1CBqhm3nV+o^EDWh`*qe~T|Yc-==4WnBvqgx%LdmW=k1EWVH
zqbCqGF?u#LdbTinH8Xm(F#5DJ`gAb*0#PTUUpJ#)52HU2^)d$ZF$VTC22NlMoX8kB
zi7{v*V-S#>%oq$rQy4?0GKNfJ44uvxI)gC`h-NZ|&0-7(qS@?b!5r36oQ}zyZrNO3
zMO=Or+<~>+A&uN&E!^Sl+>xE!QC-|oJv`ApDhqC^EWD|@=#J`=d#Xzxs4ah}w&Jnc
z$|q_opQ^2TrnVZ0o~wh<3t%W&f<tNc(Fvx&VC63f@(X4V5O7Fnm=6N`&!0cPZsO%v
z3=B;Ao-U3d6}R4ANDmGU6lr~^!Nn0K;_9?HfJbVIkW)*G%Yg&F)*BmaZ)6Dl_&?vn
za8gV0`@6<5-|YBa|J|21FVarliS1gU$698&iU*DCL=pdt&mR>lvYGe#$xqda2bR_R
zvPYgMcHgjZ5nSA^lJr%;<&0do;O^tDDh~=pIxA#coaCY>&N%M2<a5l9V~;L&ZJD?F
zD6?3<TgqciA=l+!=Lp=a%2;%{dX@{HT-OP1|K<}HAM1TO7OY<MaYyH#Pk)4WR?Ts}
zSNX4tLr#6-^m$z!Pd18IzSivQkh7k6T`o7OKThT4#m*F4b=OPt(kAX%9+=X!JT9f}
zc|=Oray6sl!J;#tXm&@~>^tq^U%3DB@ynvKo}b?yu-bFc-u0JHzced$sg7S3zqI(2
z#Km{dPr7I=pQ5>FuK#)QwK?Y`E`B?nP+}U)I#c1+FM*1kNvWG|a(TpksZQ3B@sD~b
z<q`EIyVgP^b`|@{uDX5oB6GTR%^Or)?eBf<KkJg@eR6BbGYJ*-U;nQCudos6R9mG`
zc=6fn-^`2s)0Hm%cpbX>pQ2)*V*TdwjFOtHvV|;OsiDqHi=6%)o4b!)x$)%9pGTsE
z-JL={-Ffv+T87W(Xpooq<`r*VzWQcgBN$$`u}f>-ZQI1BB8ykN*=e4rIsJx9>z}*o
zo~|9<SN`RwE}r7KC~Q%?|CMD5O&m%cKw{Bn6{qJbmFIooO_;g=+H+v4V(@hJb6Mw<
G&;$S>I;xof

literal 0
HcmV?d00001

diff --git a/frontend/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/frontend/app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000000000000000000000000000000000000..4d6372eebdb28e45604e46eeda8dd24651419bc0
GIT binary patch
literal 1443
zcmb`G{WsKk6vsdJTdFg%tJav9_E4vzrOaqkWF|A724Nly!y+?N9`Y<EGuRA6NX2Md
zPqmGQbJPjRLrI#9?bL25ZHra>V6wZ}5(X(D_N(?!*n3`|_r0Hc?=PQw&*vnU?QTFY
zB_M<hJUv`}aj#i9>sH|!j$PP;I}?dppoE_gA(4uc!jV&0!l7_;&p2^pxNo>PEcNJv
za5_RT$o2Mf!<+r?&EbHH6nMoTsDOa;mN(wv8RNsHpG)`^ymG-S5By8<s&Q-yp4r*9
z(t|8L&`vhm$wAg!MByQdFQW1h)eqSS&@P++v^xmx2}OHF$WDZ4QHUN37S3Sd0#=@|
zD*$YR!8QbJ55gWH>=l9iVXzN_eG%Xg2@Xeq76tTZ*dGh~<G>Lo9vl;Zfs+W#BydUw
zCkZ$o1LqWQO$FC9aKlLl*7x9^0q%0}$OMlp@Kk_jHXOjofdePND+j!A{q!8~Jn+s3
z?~~w@4?egS02}8NuulUA=L~QQfm;MzCGd)XhiftT;+zFO&JVyp2mBww?;QByS_1w!
zrQlx%{^cMj0|Bo1FjwY@Q8?Hx0cIPF*@-ZRFpPc#bBw{5@tD(5%sClzIfl8WU~V#u
zm5Q;_F!wa$BSpqhN>W@2De?TKWR*!ujY;Yylk_X5#~V!L*Gw~;$%<BT_6>4Q8~Mad
z@`-kG?yb$a9cHIApZDVZ^U6Xkp<*4rU82O7%}0jjHlK{id@?-wpN*fCHXyXh(bLt*
zPc}H-x0e4E&nQ>y%B-(EL=9}RyC%MyX=upHuFhAk&MLbsF0LP-q`XnH78@fT+pKPW
zu72MW`|?8h<N~B$l%}NU6KvLZj~&>t^tz$iC}ZwLp4tB;Q49K!QCF3@!iB1qOI=?w
z7In!}F~ij(18UYUjnbmC!qKhPo%24?8U1x{7o(+?^Zu0Hx81|FuS?bJ0jgBhEMzf<
zCgUq7r2OCB(`XkKcN-TL>u5y#dD6D!)5W?`O5)V^>jb)P)GBdy%t$uUMpf$SNV31$
zb||OojAbvMP?T@$h_ZiFLFVHDmbyMhJF|-_)HX3%m=CDI+ID$0^C>kzxprBW)hw(v
zr!Gmda);ICoQyhV_oP5+C%?jcG8v+D@9f?Dk*!BxY}dazmrT@64UrP3hlslANK)bq
z$67n83eh}OeW&SV@HG95P|bjfqJ7gw$e+`Hxo!4cx`jdK1bJ>YDSpGKLPZ^1cv$ek
zIB?0S<#tX?SJCLWdMd{-ME?$hc7A$zBOdIJ)4!KcAwb=VMov)nK;9z>x~rfT1>dS+
zZ6#`2v@`jgbqq)P22H)Tx2CpmM^o1$B+xT6`(v%5xJ(?j#>Q$+rx_R|7TzDZe{J6q
zG1*EcU%tE?!kO%^M;3aM6JN*LAKUVb^xz8-Pxo#jR5(-KBeLJvA@-gxNHx0M-ZJLl
z;#JwQoh~9V?`UVo#}{6ka@II>++D@%KqGpMdlQ}?9E*wFcf5(#XQnP$Dk5~%iX^>f
z<NEXJGYh+`9LE^Z1#g~OZ)yl?O>%$y;?M0BLp{O3a(-4A?ewryHrrD%cx#Q^%KY1H
zNre$ve+vceSLZcNY4U(RBX&)oZn*Py()h)XkE?PL$!bNb{N5FVI2Y%LKEm%yvpyTP
z(1P?z<YzdcoCZ;A^sD<`wcO1=DLw>~7YxD~Rf<<Lt&2H?f`^~9TW?0O(WnyXeZvF-
hHxv6WEXUT@T$j&O|7sZ6iSVC<kf$5l^{TT-@h=>(a@_y`

literal 0
HcmV?d00001

diff --git a/frontend/app/android/app/src/main/res/values-night/styles.xml b/frontend/app/android/app/src/main/res/values-night/styles.xml
new file mode 100644
index 0000000..06952be
--- /dev/null
+++ b/frontend/app/android/app/src/main/res/values-night/styles.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
+    <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
+        <!-- Show a splash screen on the activity. Automatically removed when
+             the Flutter engine draws its first frame -->
+        <item name="android:windowBackground">@drawable/launch_background</item>
+    </style>
+    <!-- Theme applied to the Android Window as soon as the process has started.
+         This theme determines the color of the Android Window while your
+         Flutter UI initializes, as well as behind your Flutter UI while its
+         running.
+
+         This Theme is only used starting with V2 of Flutter's Android embedding. -->
+    <style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
+        <item name="android:windowBackground">?android:colorBackground</item>
+    </style>
+</resources>
diff --git a/frontend/app/android/app/src/main/res/values/styles.xml b/frontend/app/android/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..cb1ef88
--- /dev/null
+++ b/frontend/app/android/app/src/main/res/values/styles.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
+    <style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
+        <!-- Show a splash screen on the activity. Automatically removed when
+             the Flutter engine draws its first frame -->
+        <item name="android:windowBackground">@drawable/launch_background</item>
+    </style>
+    <!-- Theme applied to the Android Window as soon as the process has started.
+         This theme determines the color of the Android Window while your
+         Flutter UI initializes, as well as behind your Flutter UI while its
+         running.
+
+         This Theme is only used starting with V2 of Flutter's Android embedding. -->
+    <style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
+        <item name="android:windowBackground">?android:colorBackground</item>
+    </style>
+</resources>
diff --git a/frontend/app/android/app/src/profile/AndroidManifest.xml b/frontend/app/android/app/src/profile/AndroidManifest.xml
new file mode 100644
index 0000000..399f698
--- /dev/null
+++ b/frontend/app/android/app/src/profile/AndroidManifest.xml
@@ -0,0 +1,7 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- The INTERNET permission is required for development. Specifically,
+         the Flutter tool needs it to communicate with the running application
+         to allow setting breakpoints, to provide hot reload, etc.
+    -->
+    <uses-permission android:name="android.permission.INTERNET"/>
+</manifest>
diff --git a/frontend/app/android/build.gradle b/frontend/app/android/build.gradle
new file mode 100644
index 0000000..f7eb7f6
--- /dev/null
+++ b/frontend/app/android/build.gradle
@@ -0,0 +1,31 @@
+buildscript {
+    ext.kotlin_version = '1.7.10'
+    repositories {
+        google()
+        mavenCentral()
+    }
+
+    dependencies {
+        classpath 'com.android.tools.build:gradle:7.3.0'
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+    }
+}
+
+allprojects {
+    repositories {
+        google()
+        mavenCentral()
+    }
+}
+
+rootProject.buildDir = '../build'
+subprojects {
+    project.buildDir = "${rootProject.buildDir}/${project.name}"
+}
+subprojects {
+    project.evaluationDependsOn(':app')
+}
+
+tasks.register("clean", Delete) {
+    delete rootProject.buildDir
+}
diff --git a/frontend/app/android/gradle.properties b/frontend/app/android/gradle.properties
new file mode 100644
index 0000000..94adc3a
--- /dev/null
+++ b/frontend/app/android/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.jvmargs=-Xmx1536M
+android.useAndroidX=true
+android.enableJetifier=true
diff --git a/frontend/app/android/gradle/wrapper/gradle-wrapper.properties b/frontend/app/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..3c472b9
--- /dev/null
+++ b/frontend/app/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
diff --git a/frontend/app/android/settings.gradle b/frontend/app/android/settings.gradle
new file mode 100644
index 0000000..55c4ca8
--- /dev/null
+++ b/frontend/app/android/settings.gradle
@@ -0,0 +1,20 @@
+pluginManagement {
+    def flutterSdkPath = {
+        def properties = new Properties()
+        file("local.properties").withInputStream { properties.load(it) }
+        def flutterSdkPath = properties.getProperty("flutter.sdk")
+        assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
+        return flutterSdkPath
+    }
+    settings.ext.flutterSdkPath = flutterSdkPath()
+
+    includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
+
+    plugins {
+        id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false
+    }
+}
+
+include ":app"
+
+apply from: "${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle/app_plugin_loader.gradle"
diff --git a/frontend/app/ios/.gitignore b/frontend/app/ios/.gitignore
new file mode 100644
index 0000000..7a7f987
--- /dev/null
+++ b/frontend/app/ios/.gitignore
@@ -0,0 +1,34 @@
+**/dgph
+*.mode1v3
+*.mode2v3
+*.moved-aside
+*.pbxuser
+*.perspectivev3
+**/*sync/
+.sconsign.dblite
+.tags*
+**/.vagrant/
+**/DerivedData/
+Icon?
+**/Pods/
+**/.symlinks/
+profile
+xcuserdata
+**/.generated/
+Flutter/App.framework
+Flutter/Flutter.framework
+Flutter/Flutter.podspec
+Flutter/Generated.xcconfig
+Flutter/ephemeral/
+Flutter/app.flx
+Flutter/app.zip
+Flutter/flutter_assets/
+Flutter/flutter_export_environment.sh
+ServiceDefinitions.json
+Runner/GeneratedPluginRegistrant.*
+
+# Exceptions to above rules.
+!default.mode1v3
+!default.mode2v3
+!default.pbxuser
+!default.perspectivev3
diff --git a/frontend/app/ios/Flutter/AppFrameworkInfo.plist b/frontend/app/ios/Flutter/AppFrameworkInfo.plist
new file mode 100644
index 0000000..9625e10
--- /dev/null
+++ b/frontend/app/ios/Flutter/AppFrameworkInfo.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>CFBundleDevelopmentRegion</key>
+  <string>en</string>
+  <key>CFBundleExecutable</key>
+  <string>App</string>
+  <key>CFBundleIdentifier</key>
+  <string>io.flutter.flutter.app</string>
+  <key>CFBundleInfoDictionaryVersion</key>
+  <string>6.0</string>
+  <key>CFBundleName</key>
+  <string>App</string>
+  <key>CFBundlePackageType</key>
+  <string>FMWK</string>
+  <key>CFBundleShortVersionString</key>
+  <string>1.0</string>
+  <key>CFBundleSignature</key>
+  <string>????</string>
+  <key>CFBundleVersion</key>
+  <string>1.0</string>
+  <key>MinimumOSVersion</key>
+  <string>11.0</string>
+</dict>
+</plist>
diff --git a/frontend/app/ios/Flutter/Debug.xcconfig b/frontend/app/ios/Flutter/Debug.xcconfig
new file mode 100644
index 0000000..592ceee
--- /dev/null
+++ b/frontend/app/ios/Flutter/Debug.xcconfig
@@ -0,0 +1 @@
+#include "Generated.xcconfig"
diff --git a/frontend/app/ios/Flutter/Release.xcconfig b/frontend/app/ios/Flutter/Release.xcconfig
new file mode 100644
index 0000000..592ceee
--- /dev/null
+++ b/frontend/app/ios/Flutter/Release.xcconfig
@@ -0,0 +1 @@
+#include "Generated.xcconfig"
diff --git a/frontend/app/ios/Runner.xcodeproj/project.pbxproj b/frontend/app/ios/Runner.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..e806580
--- /dev/null
+++ b/frontend/app/ios/Runner.xcodeproj/project.pbxproj
@@ -0,0 +1,614 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 54;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
+		3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
+		74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
+		97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
+		97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
+		97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
+		331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+		331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 97C146E61CF9000F007C117D /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 97C146ED1CF9000F007C117D;
+			remoteInfo = Runner;
+		};
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		9705A1C41CF9048500538489 /* Embed Frameworks */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 10;
+			files = (
+			);
+			name = "Embed Frameworks";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
+		1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
+		3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
+		74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
+		74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
+		7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
+		9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
+		9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
+		97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+		97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+		97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
+		97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
+		331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		97C146EB1CF9000F007C117D /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		9740EEB11CF90186004384FC /* Flutter */ = {
+			isa = PBXGroup;
+			children = (
+				3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
+				9740EEB21CF90195004384FC /* Debug.xcconfig */,
+				7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
+				9740EEB31CF90195004384FC /* Generated.xcconfig */,
+			);
+			name = Flutter;
+			sourceTree = "<group>";
+		};
+		331C8082294A63A400263BE5 /* RunnerTests */ = {
+			isa = PBXGroup;
+			children = (
+				331C807B294A618700263BE5 /* RunnerTests.swift */,
+			);
+			path = RunnerTests;
+			sourceTree = "<group>";
+		};
+		97C146E51CF9000F007C117D = {
+			isa = PBXGroup;
+			children = (
+				9740EEB11CF90186004384FC /* Flutter */,
+				97C146F01CF9000F007C117D /* Runner */,
+				97C146EF1CF9000F007C117D /* Products */,
+				331C8082294A63A400263BE5 /* RunnerTests */,
+			);
+			sourceTree = "<group>";
+		};
+		97C146EF1CF9000F007C117D /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				97C146EE1CF9000F007C117D /* Runner.app */,
+				331C8081294A63A400263BE5 /* RunnerTests.xctest */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		97C146F01CF9000F007C117D /* Runner */ = {
+			isa = PBXGroup;
+			children = (
+				97C146FA1CF9000F007C117D /* Main.storyboard */,
+				97C146FD1CF9000F007C117D /* Assets.xcassets */,
+				97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
+				97C147021CF9000F007C117D /* Info.plist */,
+				1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
+				1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
+				74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
+				74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
+			);
+			path = Runner;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		331C8080294A63A400263BE5 /* RunnerTests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
+			buildPhases = (
+				331C807D294A63A400263BE5 /* Sources */,
+				331C807E294A63A400263BE5 /* Frameworks */,
+				331C807F294A63A400263BE5 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				331C8086294A63A400263BE5 /* PBXTargetDependency */,
+			);
+			name = RunnerTests;
+			productName = RunnerTests;
+			productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
+		97C146ED1CF9000F007C117D /* Runner */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
+			buildPhases = (
+				9740EEB61CF901F6004384FC /* Run Script */,
+				97C146EA1CF9000F007C117D /* Sources */,
+				97C146EB1CF9000F007C117D /* Frameworks */,
+				97C146EC1CF9000F007C117D /* Resources */,
+				9705A1C41CF9048500538489 /* Embed Frameworks */,
+				3B06AD1E1E4923F5004D2608 /* Thin Binary */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = Runner;
+			productName = Runner;
+			productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
+			productType = "com.apple.product-type.application";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		97C146E61CF9000F007C117D /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				BuildIndependentTargetsInParallel = YES;
+				LastUpgradeCheck = 1430;
+				ORGANIZATIONNAME = "";
+				TargetAttributes = {
+					331C8080294A63A400263BE5 = {
+						CreatedOnToolsVersion = 14.0;
+						TestTargetID = 97C146ED1CF9000F007C117D;
+					};
+					97C146ED1CF9000F007C117D = {
+						CreatedOnToolsVersion = 7.3.1;
+						LastSwiftMigration = 1100;
+					};
+				};
+			};
+			buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
+			compatibilityVersion = "Xcode 9.3";
+			developmentRegion = en;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = 97C146E51CF9000F007C117D;
+			productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				97C146ED1CF9000F007C117D /* Runner */,
+				331C8080294A63A400263BE5 /* RunnerTests */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		331C807F294A63A400263BE5 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		97C146EC1CF9000F007C117D /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
+				3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
+				97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
+				97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
+			isa = PBXShellScriptBuildPhase;
+			alwaysOutOfDate = 1;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+				"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
+			);
+			name = "Thin Binary";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
+		};
+		9740EEB61CF901F6004384FC /* Run Script */ = {
+			isa = PBXShellScriptBuildPhase;
+			alwaysOutOfDate = 1;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputPaths = (
+			);
+			name = "Run Script";
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		331C807D294A63A400263BE5 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		97C146EA1CF9000F007C117D /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
+				1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+		331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 97C146ED1CF9000F007C117D /* Runner */;
+			targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
+		};
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+		97C146FA1CF9000F007C117D /* Main.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				97C146FB1CF9000F007C117D /* Base */,
+			);
+			name = Main.storyboard;
+			sourceTree = "<group>";
+		};
+		97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				97C147001CF9000F007C117D /* Base */,
+			);
+			name = LaunchScreen.storyboard;
+			sourceTree = "<group>";
+		};
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+		249021D3217E4FDB00AE95B9 /* Profile */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = iphoneos;
+				SUPPORTED_PLATFORMS = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Profile;
+		};
+		249021D4217E4FDB00AE95B9 /* Profile */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CLANG_ENABLE_MODULES = YES;
+				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+				ENABLE_BITCODE = NO;
+				INFOPLIST_FILE = Runner/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.app;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+				SWIFT_VERSION = 5.0;
+				VERSIONING_SYSTEM = "apple-generic";
+			};
+			name = Profile;
+		};
+		331C8088294A63A400263BE5 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = AE0B7B92F70575B8D7E0D07E /* Pods-RunnerTests.debug.xcconfig */;
+			buildSettings = {
+				BUNDLE_LOADER = "$(TEST_HOST)";
+				CODE_SIGN_STYLE = Automatic;
+				CURRENT_PROJECT_VERSION = 1;
+				GENERATE_INFOPLIST_FILE = YES;
+				MARKETING_VERSION = 1.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.app.RunnerTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				SWIFT_VERSION = 5.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+			};
+			name = Debug;
+		};
+		331C8089294A63A400263BE5 /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 89B67EB44CE7B6631473024E /* Pods-RunnerTests.release.xcconfig */;
+			buildSettings = {
+				BUNDLE_LOADER = "$(TEST_HOST)";
+				CODE_SIGN_STYLE = Automatic;
+				CURRENT_PROJECT_VERSION = 1;
+				GENERATE_INFOPLIST_FILE = YES;
+				MARKETING_VERSION = 1.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.app.RunnerTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_VERSION = 5.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+			};
+			name = Release;
+		};
+		331C808A294A63A400263BE5 /* Profile */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 640959BDD8F10B91D80A66BE /* Pods-RunnerTests.profile.xcconfig */;
+			buildSettings = {
+				BUNDLE_LOADER = "$(TEST_HOST)";
+				CODE_SIGN_STYLE = Automatic;
+				CURRENT_PROJECT_VERSION = 1;
+				GENERATE_INFOPLIST_FILE = YES;
+				MARKETING_VERSION = 1.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.app.RunnerTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_VERSION = 5.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
+			};
+			name = Profile;
+		};
+		97C147031CF9000F007C117D /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = iphoneos;
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Debug;
+		};
+		97C147041CF9000F007C117D /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = iphoneos;
+				SUPPORTED_PLATFORMS = iphoneos;
+				SWIFT_COMPILATION_MODE = wholemodule;
+				SWIFT_OPTIMIZATION_LEVEL = "-O";
+				TARGETED_DEVICE_FAMILY = "1,2";
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Release;
+		};
+		97C147061CF9000F007C117D /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CLANG_ENABLE_MODULES = YES;
+				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+				ENABLE_BITCODE = NO;
+				INFOPLIST_FILE = Runner/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.app;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				SWIFT_VERSION = 5.0;
+				VERSIONING_SYSTEM = "apple-generic";
+			};
+			name = Debug;
+		};
+		97C147071CF9000F007C117D /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CLANG_ENABLE_MODULES = YES;
+				CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
+				ENABLE_BITCODE = NO;
+				INFOPLIST_FILE = Runner/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.app;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+				SWIFT_VERSION = 5.0;
+				VERSIONING_SYSTEM = "apple-generic";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				331C8088294A63A400263BE5 /* Debug */,
+				331C8089294A63A400263BE5 /* Release */,
+				331C808A294A63A400263BE5 /* Profile */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				97C147031CF9000F007C117D /* Debug */,
+				97C147041CF9000F007C117D /* Release */,
+				249021D3217E4FDB00AE95B9 /* Profile */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				97C147061CF9000F007C117D /* Debug */,
+				97C147071CF9000F007C117D /* Release */,
+				249021D4217E4FDB00AE95B9 /* Profile */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 97C146E61CF9000F007C117D /* Project object */;
+}
diff --git a/frontend/app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/frontend/app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/frontend/app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "self:">
+   </FileRef>
+</Workspace>
diff --git a/frontend/app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/frontend/app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>IDEDidComputeMac32BitWarning</key>
+	<true/>
+</dict>
+</plist>
diff --git a/frontend/app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/frontend/app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..f9b0d7c
--- /dev/null
+++ b/frontend/app/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>PreviewsEnabled</key>
+	<false/>
+</dict>
+</plist>
diff --git a/frontend/app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/frontend/app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
new file mode 100644
index 0000000..87131a0
--- /dev/null
+++ b/frontend/app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "1430"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "97C146ED1CF9000F007C117D"
+               BuildableName = "Runner.app"
+               BlueprintName = "Runner"
+               ReferencedContainer = "container:Runner.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "97C146ED1CF9000F007C117D"
+            BuildableName = "Runner.app"
+            BlueprintName = "Runner"
+            ReferencedContainer = "container:Runner.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <Testables>
+         <TestableReference
+            skipped = "NO"
+            parallelizable = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "331C8080294A63A400263BE5"
+               BuildableName = "RunnerTests.xctest"
+               BlueprintName = "RunnerTests"
+               ReferencedContainer = "container:Runner.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
+      </Testables>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "97C146ED1CF9000F007C117D"
+            BuildableName = "Runner.app"
+            BlueprintName = "Runner"
+            ReferencedContainer = "container:Runner.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Profile"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "97C146ED1CF9000F007C117D"
+            BuildableName = "Runner.app"
+            BlueprintName = "Runner"
+            ReferencedContainer = "container:Runner.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/frontend/app/ios/Runner.xcworkspace/contents.xcworkspacedata b/frontend/app/ios/Runner.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..1d526a1
--- /dev/null
+++ b/frontend/app/ios/Runner.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "group:Runner.xcodeproj">
+   </FileRef>
+</Workspace>
diff --git a/frontend/app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/frontend/app/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>IDEDidComputeMac32BitWarning</key>
+	<true/>
+</dict>
+</plist>
diff --git a/frontend/app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/frontend/app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
new file mode 100644
index 0000000..f9b0d7c
--- /dev/null
+++ b/frontend/app/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>PreviewsEnabled</key>
+	<false/>
+</dict>
+</plist>
diff --git a/frontend/app/ios/Runner/AppDelegate.swift b/frontend/app/ios/Runner/AppDelegate.swift
new file mode 100644
index 0000000..70693e4
--- /dev/null
+++ b/frontend/app/ios/Runner/AppDelegate.swift
@@ -0,0 +1,13 @@
+import UIKit
+import Flutter
+
+@UIApplicationMain
+@objc class AppDelegate: FlutterAppDelegate {
+  override func application(
+    _ application: UIApplication,
+    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
+  ) -> Bool {
+    GeneratedPluginRegistrant.register(with: self)
+    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
+  }
+}
diff --git a/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..d36b1fa
--- /dev/null
+++ b/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,122 @@
+{
+  "images" : [
+    {
+      "size" : "20x20",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-20x20@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-20x20@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-29x29@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-29x29@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-29x29@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-40x40@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-40x40@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-60x60@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "60x60",
+      "idiom" : "iphone",
+      "filename" : "Icon-App-60x60@3x.png",
+      "scale" : "3x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-20x20@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "20x20",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-20x20@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-29x29@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "29x29",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-29x29@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-40x40@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "40x40",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-40x40@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-76x76@1x.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "76x76",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-76x76@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "83.5x83.5",
+      "idiom" : "ipad",
+      "filename" : "Icon-App-83.5x83.5@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "1024x1024",
+      "idiom" : "ios-marketing",
+      "filename" : "Icon-App-1024x1024@1x.png",
+      "scale" : "1x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
diff --git a/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
new file mode 100644
index 0000000000000000000000000000000000000000..dc9ada4725e9b0ddb1deab583e5b5102493aa332
GIT binary patch
literal 10932
zcmeHN2~<<px;_zwS_EvVN{bS`^-7&8R0|495bUK^D^XBHMny$s(km#6;e;!SGxj>R
zh`|8`A_PQ1nSu(UMFx?8j8PC!!VDphaL#`F42fd#7Vlc`zIE4n%Y~eiz4y1j|NDpi
z?<@|pSJ-HM`qifhf@m%MamgwK83`XpBA<+azdF#2QsT{X@z0A9Bq>~TVErigKH1~P
zRX-!h-f0NJ4Mh++{D}J+K>~~rq}d%o%+4dogzXp7RxX4C>Km5XEI|PAFDmo;DFm6G
zzjVoB`@qW98Yl0Kvc-9w09^PrsobmG*Eju^=3f?0o-t$U)T<Vs-_ptGc%r}RxlL{U
z594Nx3LSCiY>L1B<av%wl~eUs+RM37tq097oi466Ni7&}9zE55-Df7QK`jObjk_8*
z2=WZ7JR3p(H*qD^m5b(X6AJ6+g2O+ogtkrA`gIw>3;sZ^!++3&bGZ!o-*6w?;oOhf
z=A+Qb$scV5!RbG+&2S}BQ6YH!FKb0``VVX~T$dzzeSZ$&9=X$3)_7Z{SspSYJ!lGE
z7yig_41zpQ)%5dr4ff0rh$@ky3-JLRk&DK)NE<G~28nz*$O+TWt1-`o21&!^8fpkq
z%4%l9b!-rW!W?9SDEuCRSYrFhL8%ToSju{TFz-VEme`eH0T5fO(BEZ111RaK=Dg2f
z5CA<GgJu)lNd`&)+P*)UFcbi7{1u!*(1QX&We5OLnc*-Ptll30XnGL+PZb_SPsQL}
z06tpEaz~IDlnr1qMB$6E{S1UF*O2PKKx$@|vS8Q}gK&;&&<0Z@2c<gXAPqoUN@xu&
zC8UD;{7ERNw0=h_sQ_Q8<O260xxjr0E;Lbh<j%-Ha3j}n<%77rvxYWqXh3psC7{D}
zNS$CPLpT1>IHecf9c*?Z1bUB4%pZjQ7hD!A0r-@NF(^WKdr(LXj|=UE7?gBYGgGQV
zidf2`ZT@pzXf7}!NH4q(0IMcxsUGDih(0{kRSez&z?CFA0RVXsVFw3^u=^KMtt95q
z43q$b*6#uQDLoiCAF_{RFc{!H^moH_cmll#Fc^KXi{9GDl{>%+3qyfOE5;Zq|6#Hb
zp^#1G+z^AXfRKaa9HK;%b3Ux~U@q?xg<2DXP%6k!3E)PA<#4$ui8eDy5|9hA5&{?v
z(-;*1%(1~-NTQ`Is1_MGdQ{+i*ccd96ab$R<XtXg*@mJK!a|}%F@r=&)jv#>$T3=%
zw_KuNF@vI!A>>Y_2pl9L{9h1-C6H8<)J4gKI6{WzGBi<@u<rqo5ir=8p#f-1iNUua
zG_>3P6hNsXG=bRq<Fp<E9Rd*apg=S|QkjnvXlMYMp3xw055WK?;9!B24Bi1CQUto0
z^tRrhu>5c+z;Gc3VUCe;LIIFDmQAGy+=mRyF++u=drBWV8-^>0yE9N&*05XHZpPlE
zxu@?8(ZNy7rm?|<+UNe0Vs6&o?l`Pt>P&WaL~M&#Eh%`rg@Mbb)J&@DA-wheQ>hRV
z<dbay5!oN}MCAg}b`Vc1N${bcU_OPzf=6^iM5FWXJQ3X%5hcVnLqD-Wf*L%p$xao@
zN<DEMcXZBHZ9e%+)=snX)kJy|9YX22Ks1grJt^DVj#?T$s`eD&W<BKf><(XhigZAT
z>=M;URcdCaiO3d^?H<^EiEMDV+7HsTiOhoaMX%P65E<(5xMPJKxf<DYP<EbL{d#Uj
zI@Nlzw<e6Nb)Yud@_omNRn$gFA+mo`Q`5BC|I+>!0u>U~uVqnPN7T!X!o@_gs3Ct1
zlZ_$5QXP4{Aj645wG_SNT&6m|O6~Tsl$q?nK*)(`{J4b=(yb^nOATtF1_aS978$x3
zx>Q@s4i3~IT*+l{@dx~Hst21fR*+5}S1@cf>&8*uLw-0^zK(+OpW?cS-YG1QBZ5q!
zgTAgivzoF#`cSz&HL>Ti!!v#?36I1*l^mkrx7Y|K6L#n!-~5=d3;K<;Zqi|gpNUn_
z_^GaQDEQ*jfzh;`j&<KtiXoiC4mK3L{WRAJ^u*s>KXb66fWEk1K7vxQIMQ_#Wu_%3
z4Oeb7FJ`8I>Px;^S?)}2+4D_83gHEq>8qSQY0PVP?o)zAv3K~;R$fnwTmI-=ZLK`=
zTm+0h*e+Yfr(IlH3i7gUclNH^!MU>id$Jw>O?2i0Cila#v|twub21@e{S2v}8Z13(
zNDrTXZVgris|qYm<0NU(tAPouG!QF4ZNpZPkX~{tVf8xY690JqY1NVdiTtW+NqyRP
zZ<nMcELAP(N#OsYS|XB|y<MV68}W8Yc5tierTAX3NcF;g5S*!cDb5LwR=uzv1|L_w
z6z2s8s9xBQn_2PlR0b)*I!Elfil#9i+-er9TN3@?>&;T0ikb8V{wxmFhlLTQ&?OP7
z;(z*<+?J2~z*6asSe7h`$8~Se(@t(#%?BGLVs$p``;CyvcT?7Y!{tIPva$LxCQ&4W
z6v#F*);|RXvI%qnoOY&i4S*EL&h%<YHH?QUsCqWSwg24-)<J#9O%FNw6Us-S>hP3O
zLsrFZhv&Hu<OV6sfD=@+ekb-;V%=oGqN?1{8~N{DqA_Ls0q|Maw!6Eo+zIsQK8M~&
zz(wep$VKCAzxR)$u2Dn`hkV-o$=E2o;_IRjvD7VxieIFZj$MRQkh*rzDshzxMbUyn
z?J3E*@;s;}JTjy3B<MDG;?@dPr0y)l6rx2}P4VISo02I-?E$@HN&68V`;@0)(?i9A
zCFVgnk`11du7<%xOd)Q3<P>5tF$Lx!8(hs&?!Kx5&L(fdu}UI5d*wn~A`nPUhG&Rv
z2#ixiJdhSF-K2tpVL=)5UkXRuPAFrEW}7mW=uAmtVQ&<Llg2_1oIfV}Eteyh=b{nU
z(k$Y$Itw+MnNj@4&yk=M`|y0`)@nud!=QruqNsnA0ZIHBPXp|Ar9AR@V0#gMT64tM
zfsx4b>pGE-&az6@#-(Te^n*lrH^m@X-ftVcwO_#7{WI)5v(?>uC9GG{lcGXYJ~Q8q
zbMFl7;t+kV;|;KkBW2!P_o%Czhw&Q(nXlxK9ak&6r5t_KH8#1Mr-*0}2<v7r$WOgR
zsKsU6`s{)8k-`p9L%xIaOz8eZ#`#O~qJt8aj<KfkL1IYSkS|Ev0G;ZtW>h8R9XNkr
zto5-b7P_auqTJb(TJlmJ9xreA=6d=d)CVbYP-r4$hDn5|TIhB>SReMfh&OVLkMk-T
zYf%$taLF0OqYF?V{+6Xkn>iX@TuqQ?&cN6UjC9YF&%q{Ut3zv{U2)~$>-3;Dp)*(?
zg*$mu8^i=-e#acaj*T$pNowo{xiGEk$%DusaQiS!KjJH96XZ-hXv+jk%ard#fu=@Q
z$AM)YWvE^{%tDfK%nD49=PI|wYu}lYVbB#a7wtN^Nml@CE@{Gv7+jo{_V?I*jkdLD
zJE|jfdrmVbkfS>rN*+`#l%ZUi5_bMS<>=MBDNlpiSb_tAF|Zy`K7kcp@|d?yaTmB^
zo?(vg;B$vxS|SszusORgDg-*Uitzdi{dUV+glA~R8V(?`3GZIl^egW{a919!j#>f`
znL1o_^-b`}xnU0+<Ar!V8w<0JQSzPU1pIC|uk)>~KIFLQ)$Q6#ym%)(GYC`^XM*{g
zv3AM5$+TtDRs%`2TyR^$(hqE7Y1b&`Jd6dS6B#hDVbJlUXcG3y*43<C=mO&Nf=@Kw
zRc+w{Y~8#efee$iAX6WRh;xh-t9K0$q)O0^qrvGiT;>9D8MrK!2D~6gn>UD4Imctb
z+IvAt0iaW73Iq$K?4}H`7wq6YkTMm`tcktXgK0lKPmh=>h+l}Y+pDtvHnG>uqBA)l
zAH6BV4F}v$(o$8Gfo*PB>IuaY1*^*`OTx4|hM8jZ?B6HY;F6p4{`OcZZ(us-RVwDx
zUzJrCQlp@mz1ZFiSZ*$yX3c_#h9J;yBE$2g%xjmGF4c<x8WCOv_jFlKGTcdj@|Z>a
z&yL`nGVs!Zxsh^j6i%$a*I3ZD2SoNT`{D%mU=LKaEwbN(_J5%i-6Va?@*>=3(dQy`
zOv%$_9lcy9+(t>qohkuU4r_P=R^6ME+wFu&LA9tw9RA?azGhjrVJKy&<zA^6FZGLW
z&j49!=<hsCD<}@cT^PBI+T`TlG2u=5E46~#(vqFvcHwLg5(H}YTkKxgncNkQ(Q$iq
z9VmBo#Ol<dby?lD6R^$EVR*Xm%ue*D6$7^@t)f<gIRcA*%kItnIYsNzaT^1L?oTpY
z=g~^gL8qzvW(nHxSVP@*;FzPrO`)wQGSdNLsucoPA)TQ{mvQmltqn)fv<3TM1?X`R
zW_sWcW?M+pYpwvhzF!d9aL0I%0qlg>8=*qZT5Dr8g--d+S8zAyJ$1HlW3Olryt`yE
zFIph~Z6oF&o64rw{>lgZISC6p^CBer9C5G6yq%?8tC+)7*d+ib^?fU!JRFxynRLEZ
zj;?PwtS}Ao#9whV@KEmwQgM0TVP{hs>dg(1*DiMUOKHdQGIqa0`yZnHk9mtbPfoLx
zo;^V6pKUJ!5#n`w2D&381#5#_t}AlTGEgDz$^;u;-vxDN?^#5!zN9ngytY@oTv!nc
zp1Xn8uR$1Z;7vY`-<*?DfPHB;x|GUi_fI9@I9SVRv1)qETbNU_8{5U|(>Du84qP#7
z*l9Y$SgA&wGbj>R1YeT9vYjZuC@|{rajTL0f%N@>3$DFU=`lSPl=Iv;EjuGjBa$Gw
zHD-;%YOE@<-!7-Mn`0WuO3oWuL6tB2cpPw~Nvuj|KM@))ixuDK`9;jGMe2d)7gHin
zS<>k@!x;!TJEc#HdL#RF(`|4W+H88d4V%zlh(7#{q2d0OQX9*FW^`^_<3r$kabWAB
z$9BONo5}*(%<q#${l(a3AVQruJ#!=UBQkBV-bu0rJvnH9b6fKOuXV+U+3Fe(4hcmv
zHL_S|!(7nkhwr=AU5(083o}8lBhN7wUly*&*<g=_KjF|3av}p4?DLTRV(aJY&r>kx
zOXi-yM_cmB3>inPpI~)duvZykJ@^^aWzQ=eQ&STUa}2uT@lV&WoRzkUoE`rR0)`=l
zFT%f|LA9fCw>`enm$p7W^E@U7RNBtsh{_-7vVz3DtB*y#*~(L9+x9*wn8VjWw|Q~q
zKFsj1Yl>;}%MG3=PY`$g$_mnyhuV&~O~u~)968$0b2!Jkd;2MtAP#ZDYw9hmK_+M$
zb<EtNf3AOGxJvI6w{YOjmsO)>3pxyYC&|CuAbtiG8HZjj?MZJBFbt`ryf+c1dXFuC
z0*ZQhBzNBd*}s6K_G}(|Z_9NDV162#y%WSNe|FTDDhx)K<Y*_;T<QjkM@x-@IglV;
zWhPqzW}V}p)efCgi|4y24=STrIS3OS6_&?>!c(mMJh@h87@8(^YdK$&d*^WQe8Z53
z(|@MRJ$Lk-&ii74MPIs80WsOFZ(NX23oR-?<cI&3<Ad*?Kl;}0z^Ak5gm~_O39(|1
zQ$ay*GF}l=Z;>As+*aq6b?~62@fSVmM-_*cb1RzZ)`5$agEiL`-E9s7<Jb3fXRR;Q
zK=W?&TAPiYSGZk9mzWj-o}N08TxQ5w)`XoCzM9!vj*2x<b7seEGjyYyVTks?J(mk3
zD<ycFV{|M{LoXRm{zZdxuw*^h@!AvFaUqK-n_6tl#10#W7KYEUIubUYPLY;)JiiF@
z%xuD)UW#R7(5Dt<J74H%pXC_a_v&I>{GM2?(KNPgK1(+c*|-FKoy}X(D_b#etO|YR
z(BGZ)0Ntfv-7R4GHoXp?l5g#*={S1{u-QzxCGng*oWr~@X-5f~RA14b8~B+pLKvr4
zfgL|7I>jlak9>D4=(i(cqYf7#3<K=g&thwf-1wQnLc@^pQ~c9dexWxSS2F2H$I8(%
zCKf6GcHJAdW1Mu34%7g&I?gU_wDz&s7*IpEBSuf<b6CA|*H$IXd3Ln*a+Y4kJ-1`s
zd&F&S7s{<U7W2ki#lQSa>18!OSR=^`xxvI!bBlS??`xxWeg?+|>MxaIdH1U~#1tHu
zB{QMR?EGRmQ_l4p6YXJ{o(hh-7Tdm>TAX3<mFD{3>80TZZZyVkqHNzjUn*_|cb?T?
zt;d2s-?B#Mc>T-gvBmQZx(<G=%x~?x_%h*<whB;F)t~G8F#FpTBMP>y_cfkXZO~{N
zT6rP7SD6g~n9QJ)8F*8uHxTLCAZ{l1Y&?6v)BOJZ)=R-pY=Y=&1}jE7fQ><K_`oOa
z-x_HB-c`JI%+cKk>USS}xP#exo57uND0i*rEk@$;nLvRB@u~s^dwRf?G?_enN@$t*
zbL%JO=rV(3Ju8#GqUpeE3l_Wu1lN9Y{D4uaUe`g>zlj$1ER$6S6@{m1!~V|bYkhZA
z%CvrDRTkHuajMU8;&RZ&itnC~iYLW4DVkP<$}>#&(`UO>!n)Po;Mt(SY8Yb`AS9lt
znbX^i?Oe9r_o=?})IHKHoQGKXsps_SE{<f3-SFt<Sda6papQe8cP?}Fr-Q({2GNZJ
z#e2>hwrg?6dMI|^+$CeC&z@*LuF+P`7LfZ*yr+KN8B4{Nzv<`A(wyR@!|gw{zB6Ha
ziwPAYh)oJ(nlqSknu(8g9N&1hu0$vFK$W#mp%>X~AU1ay+EKW<nmfK^VduTXK+l*3
zB~-x9NMvYV#U*+7OMVUPx<UKM@_<QpsKia?L3~AQxydv;r<o-P%YD}Qsv>cFdif{%
z#4!<fhcS%};@jNJbjRBUxg-)_lt-oMy9=d4f3u4Ni)+HQU^9)_B{F(l!7|Ufk~fL|
z(>4aoVVJ;ULmkQf!ke2}3hqxLK>eq|-d7Ly7-J9zMpT`?dxo6HdfJA|t)?qPEVBDv
z{y_b?4^|YA4%WW0VZd8C(ZgQzRI5(I^)=Ub`Y#MHc@nv0w-DaJAqsbEHDWG8Ia6ju
zo-iyr*sq((gEwCC&^TYBWt4_@|81?=B-?#P6NMff(<j4wHgT5Or7_ecFhz6I>*^re
zYqvDuO`K@`mjm_Jd;mW_tP`3$cS?R$jR1ZN09$YO%_iBqh5ftzSpMQQtxKFU=FYmP
zeY^jph+g<4>YO;U^O>-NFLn~-RqlHvnZl2yd2A{Yc1G@Ga$d+Q&(f^tnPf+Z7s<SI
z+)&gG-ua<UmS5?=XhwO8=ep(PCbSk;lNhyoo2mtFX<23V@Jj>erIU};17+2DU_f4Z
z@GaPFut27d?!YiD+QP@)T=77cR9~MK@bd~pY%X(h%L={{OIb8IQmf-!xmZkm8A0Ga
zQSWONI17_ru5wpHg3jI@i9D+_Y|pCqVuHJNdHUauTD=R$J<sttH33i$?ow|qGlfAH
zZ@OuO*H-eDLi!ipGs#eaIYNffhhE`03^H%{55`rt`k>cD2K_liQisqG$(sm=k9;L*
z!L?*4B~ql7uioSX$zWJ?;q-SWXRFhz2Jt4%fOHA=Bwf|RzhwqdXGr78y$J)LR7&3T
zE1WWz*>GPWKZ0%|@%6=fyx)5rzUpI;bCj>3RKzNG_1w$fIFCZ&UR0(7S?g}`&Pg$M
zf`SLsz8wK82Vyj7;RyKmY{a8G{2BHG%w!^T|Njr!h9TO2LaP^_f22Q1=l$QiU84ao
zHe_#{S6;qrC6w~7{y(hs-?-j?lbOfgH^E=XcSgnwW*eEz{_Z<_<N0RuOw7Ljex{L;
nnUT@n#mUiw7WnvW+`4(shZks0)clfg*3utVEJ?6(|HuCTyjb6M

literal 0
HcmV?d00001

diff --git a/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
new file mode 100644
index 0000000000000000000000000000000000000000..7353c41ecf9ca08017312dc233d9830079b50717
GIT binary patch
literal 295
zcmV+?0oeYDP)<h;3K|Lk000e1NJLTq000yK000yS0{{R3x>xN#0001NP)t-s|Ns9~
z#rXRE|M&d=0au&!`~QyF`q}dRnBDt}*!qXo`c{v<liT|#w)Vf&=I{Fc;Pw9Z`ux7>
z{Djr|@Adh0(D_%#_&mM$D6{kE_x{oE{l@J5@%H*?%=t~i_`ufYOPkAEn!pfkr2$fs
z652Tz0001XNkl<Z7}K4Q$qs`s3<WVUZPSpj?>qeeKN4RM4i{jKqmiC$?+xN>3Apn^
z0QfuZLym_5b<*QdmkHjHlj811{If)dl(Z2K0A+ekGtrFJb?g|wt#k#pV-#A~bK=OT
ts8>{%cPtyC${m|1#B1A6#u!Q;umknL1chzTM$P~L002ovPDHLkV1lTfnu!1a

literal 0
HcmV?d00001

diff --git a/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..797d452e458972bab9d994556c8305db4c827017
GIT binary patch
literal 406
zcmV;H0crk;P)<h;3K|Lk000e1NJLTq001Ze001Zm0{{R3yC6tk0001rP)t-s|Ns9~
z#rOeNn<=*T@cRC4&iUu}{?YIKbkO<t{r_Rg`SSb!?D_s{&H1p);C<8j-t_+S`~U6q
z`B238{Qm!3$oMh2_TcODCa>)>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN
zo!<LHzxPSJ@i4UU+UD@q<nIk_s|j3`3t5Q^SB6%oxX}Or0LMv0K~y-)?T|?lf-n>X
zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY
zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW
z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7<pBH$sJ!Z4uL5R#lHLQMbsjPyu3lS&P#-eI
z`6<26X6SmpL7JKc%xiDVU{Pl_!$sZ9a08>{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx
ACIA2c

literal 0
HcmV?d00001

diff --git a/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
new file mode 100644
index 0000000000000000000000000000000000000000..6ed2d933e1120817fe9182483a228007b18ab6ae
GIT binary patch
literal 450
zcmV;z0X_bSP)<h;3K|Lk000e1NJLTq002Ay002A)0{{R34I(K(0001lP)t-s|Ns9~
z#rP?<_5oL$SH}2R$N25}{-ogh<M#fP+xy+~{#%p3>iGWQ_5NJQ_~rNh*z)}eT%KUb
z`7gNk0#AwF^#0T0?hIa^`~Ck;!}#m+_uT050aTR(J!bU#|IzRL%<lbB#Q5Uu^d+k2
z=<oI?ukI$R=x3Y5T$8^FSCIxweE~vt7!iLQ0002_Nkl<ZNXPBd*$#p*5J1sd7O_$`
zL2y9@cm4nWvj#$kn3N2CAVlsX$w}KOB~w%1>^UsMS#KsYnTF*!YeDOytlP4VhV?b}
z%rz_<=#CPc)tU1MZTq~*2=8~iZ!lSa<{9b@2Jl;?IEV8)=fG217*|@)CCYgFze-x?
zIFODUIA>nWKpE+bn~n7;-89sa>#DR>TSlqWk*!2hSN6D~Qb#VqbP~4Fk&m`@1$JGr
zXPIdeRE&b2Thd#{MtDK$px*d3-Wx``>!oimf%|A-&-q*6KAH)e$3|6JV%HX{Hig)k
suLT-RhftRq8b9;(V=235Wa|I=027H2wCDra;{X5v07*qoM6N<$f;9x^2LJ#7

literal 0
HcmV?d00001

diff --git a/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
new file mode 100644
index 0000000000000000000000000000000000000000..4cd7b0099ca80c806f8fe495613e8d6c69460d76
GIT binary patch
literal 282
zcmV+#0p<RQP)<h;3K|Lk000e1NJLTq0012T0012b0{{R3VNI7k00018P)t-s|Ns9~
z#rP?<_5oL$`~LrB%lY{I|Jw8ZvE}@&<NRF6_#kYjrQ!RX-urIO`M2l%l-v6OR+-lE
z{q_0#LcjMxzV|k|_lCRKdZ){Ir^+0L!WDhE7ImlrRF(lrfr8uVB>(^bcu7P-R4C8Q
z&e;xxFbF_Vrezo%_kH*OKhshZ6BFpG-Y1e10`QXJKbND7AMQ&cMj<Rt#L#B&<}(k`
z&v(Q6!rV_O+)5cqL@s8;Rzfa9z}^^#8AwrQTna*FxEVpNbhuQB&g))Tm50r`l1Aal
gdM1U(lMx>60B5TNObaZxYybcN07*qoM6N<$g3m;S%K!iX

literal 0
HcmV?d00001

diff --git a/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..fe730945a01f64a61e2235dbe3f45b08f7729182
GIT binary patch
literal 462
zcmV;<0WtoGP)<h;3K|Lk000e1NJLTq0024w0024&0{{R3)@8aH0001%P)t-s|Ns9~
z#rOeNn<=*Tp5FVy>-}iV`2<;=$?g5M=KQbZ{F&YRNy7Nn@%_*5{gvDM0aKI4?ESmw
z{NnZg)A0R`+4?NF_RZexyVB&^^ZvN!{I28tr{Vje;QNTz`dG&Jz0~Ek&f<Ki%5tK}
z7<#M$PKy9Rbn5v2y6F7V;_h?9>2;*Z7>B|cg}xYpxEFY+0YrKLF;^Q+-HreN0P{&i
zK~zY`?b7ECf-n?@;d<&orQ*Q7KoR%4|C>{W^h6@&01>0SKS`dn{Q}GT%Qj_{PLZ_&
zs`MFI#j-(>?bvdZ!8^xTwlY{qA)T4QLbY@j(!YJ7aXJervHy6HaG_2SB`6CC{He}f
zHVw(fJWApwPq!6VY7r1w-Fs)@ox~N<e>+q|w~e;JI~C4Vf^@d>Wvj=fl`^u9x9wd9
zR%3*Q+)t%S!MU_`id^@&Y{y7-r98lZX0?YrHlfmwb?#}^1b{8g&KzmkE(L>Z&)179
zp<)v6Y}pR<EODy^$f#TG0Y$V+eC{BDH50toV0pja4PB58a@&T&ng9R*07*qoM6N<$
Ef{9-9n*aa+

literal 0
HcmV?d00001

diff --git a/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
new file mode 100644
index 0000000000000000000000000000000000000000..321773cd857a8a0f0c9c7d3dc3f5ff4fb298dc10
GIT binary patch
literal 704
zcmV;x0zdtUP)<h;3K|Lk000e1NJLTq003720037A0{{R3Miwbv0002DP)t-s|Ns9~
z#rP?<_5oL$`~Ls={r^|S_*KRDf7JSX)B5oG{`C0!9BHKkS)BI#|MUC*n%(<~*ZTeb
z|GVh?ujKrB()j^anupf<QpEU_+WP@eji}=Lgx30GnZmQ?{7s6v0aKNr-}{c)`Z&Ay
zF1Yp=d8+|Sg#kcvxaa&jy!U#i%XOs58Hd7OmB8}){x`e#aiYgnkGvRyx&c*~05e+j
z`~TbX{-WUfio)L<X{G{5egHIG0Web~wJ>l100G2FL_t(o!|l{-Q-VMg#&MKg7c{O0
z2wJImOS3Gy*Z2Qifdv~JYOp;v+U)a|nLoc7hNH;I$;lzDt$}rkaFw1mYK5_0Q(Sut
zvbEloxON7$+HSOgC9Z8ltuC&0OSF!-mXv5caV>#bc3@hBPX@I$58-z}(ZZE!t-aOG
zpjNkbau@>yEzH(5Yj4kZiMH32XI!4~gVXNnjAvRx;Sdg^`>2DpUEwoMhTs_st8pKG
z(%SHyHdU&v%f36~uERh!bd`!T2dw;z6PrOTQ7Vt*#9F2uHlUVnb#ev_o^fh}Dzmq}
zWtlk35}k=?xj28uO|5>>$yXadTUE@@IPpgH`gJ~Ro4>jd1IF|(+IX>8M4Ps{PNvmI
zNj4D+XgN83gPt_Gm}`Ybv{;+&yu-C(Grdiahmo~BjG-l&mWM+{e5M1sm&=xduwgM9
z`8OEh`=F3r`^E{n_;%9weN{cf2%7=VzC@cYj+lg>+3|D|_1C@{hcU(DyQG_BvBWe?
zvTv``=%b1zrol#=R`JB<Q`F~GOz}zuLlL*;1}|cY-IeioVw78<ETDLaB8FiD=WNcO
mkBVDRjE_g)6gfG$f4O%7iYO|SoHw-q0000<MNUMnLSTYxO==DR

literal 0
HcmV?d00001

diff --git a/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
new file mode 100644
index 0000000000000000000000000000000000000000..797d452e458972bab9d994556c8305db4c827017
GIT binary patch
literal 406
zcmV;H0crk;P)<h;3K|Lk000e1NJLTq001Ze001Zm0{{R3yC6tk0001rP)t-s|Ns9~
z#rOeNn<=*T@cRC4&iUu}{?YIKbkO<t{r_Rg`SSb!?D_s{&H1p);C<8j-t_+S`~U6q
z`B238{Qm!3$oMh2_TcODCa>)>cdjpWt&rLJgVp-t?DREyuq1A%0Z4)6_WsQ7{nzjN
zo!<LHzxPSJ@i4UU+UD@q<nIk_s|j3`3t5Q^SB6%oxX}Or0LMv0K~y-)?T|?lf-n>X
zGXV)2i3kcZIL~_j>uIKPK_zib+3T+Nt3Mb&Br)s)UIaA}@p{wDda>7=Q|mGRp7pqY
zkJ!7E{MNz$9nOwoVqpFb)}$IP24Wn2JJ=Cw(!`OXJBr45rP>>AQr$6c7slJWvbpNW
z@KTwna6d?PP>hvXCcp=4F;=GR@R4E7<pBH$sJ!Z4uL5R#lHLQMbsjPyu3lS&P#-eI
z`6<26X6SmpL7JKc%xiDVU{Pl_!$sZ9a08>{4VU^0p4F>v^#A|>07*qoM6N<$f*5nx
ACIA2c

literal 0
HcmV?d00001

diff --git a/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..502f463a9bc882b461c96aadf492d1729e49e725
GIT binary patch
literal 586
zcmV-Q0=4~#P)<h;3K|Lk000e1NJLTq002+`002-30{{R3xz7Th0001}P)t-s|Ns9~
z#rP?<_5oL${r>+}#`wDE{8-2Mebf5<{{PqV{TgVcv*r8?UZ3{-|G?_}T*&y;@cqf{
z{Q*~+qr%%p!1pS*_Uicl#q9lc(D`!D`LN62sNwq{oYw(Wmhk)k<@f$!$@ng~_5)Ru
z0Z)trIA5^j{DIW^c+vT2%lW+2<(RtE2wR;4O@)Tm`Xr*?A(qYoM}7i5Yxw>D(&6ou
zxz!_Xr~yNF+waPe00049Nkl<ZSi|j>*;a!v6h%{rlvIH#gW3s8p;bFr=l}mRqpW2h
zw=OA%hdyL~z+UHOzl0eKhEr$YYOL-c-%Y<)=j?(bzDweB7{b+%_ypvm_cG{SvM=DK
zhv{K@m>#Bw>2W$eUI#iU)Wdgs8Y3U+A$Gd&{+j)d)BmGKx+43U_!tik_YlN)>$7G!
zhkE!s;%oku3;IwG3U^2kw?z+HM)jB{@zFhK8P#KMSytSthr+4!c(5c%+^UBn`0X*2
zy3(k600_CSZj?O$Qu%&$;|TGUJrptR(HzyIx>5E(2r{eA(<6t3e3I0B)7d6s7?Z5J
zZ!rtKvA{MiEBm&KFtoifx>5P^Z=vl)95XJn()aS5%ad(s?4-=Tkis9IG<HyCS`?qT
z)Ro|6_Qh7NQ@~}`rA+~si8eJKUPi2KvJt(SYy``QNE6~^-tErIoNIi%F$_*%27{p$
YU*-TH>u{`Fy8r+H07*qoM6N<$f<k9BS^xk5

literal 0
HcmV?d00001

diff --git a/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
new file mode 100644
index 0000000000000000000000000000000000000000..0ec303439225b78712f49115768196d8d76f6790
GIT binary patch
literal 862
zcmV-k1EKthP)<h;3K|Lk000e1NJLTq004LZ004Lh0{{R34!XwR0002zP)t-s|Ns9~
z#rObMn<=*T{Qmz~#`ydF|4G63{{H_)!1q<f`1$?*a?kkyRhf|4`b@(223wu=`~FbG
z_%68j(ctU=Ns=bC^iqtv`~3aV@cotB`eMoW_Wb_z`u;7!|0=fj9I^Fp&iOXF_5o9s
z8nN{@danRWl$6@~chULM@BMes`C`iW7K6P3OosqIa2R>20Z)wqMt%V?S?~D#06};F
zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU
z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R
zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6;
z1CV9ecD9ZEe87{{NtI*)_aJ<`<r)mO2JY~qH<i}}3%K`^CfiEV%iQNK88@tOg>kJa
z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5
zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh
z<Ot=3TnjL#{3s56++SYyJuk^V_KKHTH-gSG_ln;ze%`ptyY$>xd}eOm`fm3@MQC1<
zIk&aCj<SqPSNj*&T)V4Xl1qEFEV*8u7jv?}yd;}iuRJfwLaw8-PHA3}1zeIDmt-jy
zvzB#9ro9rV<dV$)FD&(DPu;TY*(F)noh0wk<>b~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor
zE!I71Z@ASH3grl8&P^L0Wpa<xz^6=Zk)~<jNhbH%=&&dd_9T;gIXs`jK4o;Dj*o`d
z6Z@3Wy&55W?qH8Hx+j;T<BP+>vHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@
z<lpwc2DnuIWwY0&c|FQG<a_&#RArSZ0Xg^wWdl+<xk%Z9_C`)GB_!mvPit%+KTpKq
oKffp!%tkY_plO<>Y5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU

literal 0
HcmV?d00001

diff --git a/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..0ec303439225b78712f49115768196d8d76f6790
GIT binary patch
literal 862
zcmV-k1EKthP)<h;3K|Lk000e1NJLTq004LZ004Lh0{{R34!XwR0002zP)t-s|Ns9~
z#rObMn<=*T{Qmz~#`ydF|4G63{{H_)!1q<f`1$?*a?kkyRhf|4`b@(223wu=`~FbG
z_%68j(ctU=Ns=bC^iqtv`~3aV@cotB`eMoW_Wb_z`u;7!|0=fj9I^Fp&iOXF_5o9s
z8nN{@danRWl$6@~chULM@BMes`C`iW7K6P3OosqIa2R>20Z)wqMt%V?S?~D#06};F
zA3KcL`Wb+>5ObvgQIG&ig8(;V04hz?@cqy3{mSh8o!|U|)cI!1_+!fWH@o*8vh^CU
z^ws0;(c$gI+2~q^tO#GDHf@=;DncUw00J^eL_t(&-tE|HQ`%4vfZ;WsBqu-$0nu1R
zq^Vj;p$clf^?twn|KHO+IGt^q#a3X?w9dXC@*yxhv&l}F322(8Y1&=P&I}~G@#h6;
z1CV9ecD9ZEe87{{NtI*)_aJ<`<r)mO2JY~qH<i}}3%K`^CfiEV%iQNK88@tOg>kJa
z?5=RBtFF50s;jQLFil-`)m2wrb=6h(&brpj%nG_U&ut~$?8Rokzxi8zJoWr#2dto5
zOX_URcc<1`Iky+jc;A%Vzx}1QU{2$|cKPom2Vf1{8m`vja4{F>HS?^Nc^rp}xo+Nh
z<Ot=3TnjL#{3s56++SYyJuk^V_KKHTH-gSG_ln;ze%`ptyY$>xd}eOm`fm3@MQC1<
zIk&aCj<SqPSNj*&T)V4Xl1qEFEV*8u7jv?}yd;}iuRJfwLaw8-PHA3}1zeIDmt-jy
zvzB#9ro9rV<dV$)FD&(DPu;TY*(F)noh0wk<>b~Yh%5+Yq0`)D;q{#-Uqlv*o+Oor
zE!I71Z@ASH3grl8&P^L0Wpa<xz^6=Zk)~<jNhbH%=&&dd_9T;gIXs`jK4o;Dj*o`d
z6Z@3Wy&55W?qH8Hx+j;T<BP+>vHoP|UX4e?!igT`4?AZk$hu*@%6WJ;zDOGlw7kj@
z<lpwc2DnuIWwY0&c|FQG<a_&#RArSZ0Xg^wWdl+<xk%Z9_C`)GB_!mvPit%+KTpKq
oKffp!%tkY_plO<>Y5!B-0ft0f?Lgb>C;$Ke07*qoM6N<$f~t1N9smFU

literal 0
HcmV?d00001

diff --git a/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
new file mode 100644
index 0000000000000000000000000000000000000000..e9f5fea27c705180eb716271f41b582e76dcbd90
GIT binary patch
literal 1674
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
Ux%ZwassI2007*qoM6N<$f}6Z;X#fBK

literal 0
HcmV?d00001

diff --git a/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
new file mode 100644
index 0000000000000000000000000000000000000000..84ac32ae7d989f82d5e46a60405adcc8279e8001
GIT binary patch
literal 762
zcmV<W0tNkvP)<h;3K|Lk000e1NJLTq002w?002w~0{{R3@JXQ=0002qP)t-s|Ns9~
z#rXXG|5(QODYo_jSDX9&{(;o_`ThU+`~6SD_+iQT==c3r#`s3S_Xb*>OTza`!S_YK
z_v-lm^7{VO^8Q@M_^8F)09Ki6%=s?2_5e<mRK)jOlD-01od8IZ-1Gexu=M~@mHz(!
z(eM2^yY?%;|8~&%Fu3+1v-Tvk^(eCP%G~M!P>upee(w1FB%aqSweusQ-T+CH0Xt{`
zFjMvW{@C&TB)k25()nh~_yJ9c<MsW_?fl2<{Nd~J)#L6sujeJC;K<b8pugFfyVhQm
zzhIHOPKmexK#VF>oBRL(0oO@HK~z}7?bm5j;y@69;bvlHb2tf!$ReA~x{22wTq550
z?f?Hnw(;m3ip30;QzdV~7pi!wyMYhDtXW#cO7T>|f=bdFhu+F!zMZ2UFj;GUKX7tI
z;hv3{q~!*pMj75WP_c}>6)IWvg5_yyg<9Op()eD1hWC19M@?_9_MHec{Z8n3FaF{8
z;u`Mw0ly(uE>*CgQYv{be6ab2LWhlaH1^iLIM{olnag$78^Fd}%dR7;JECQ+hmk|o
z!u<uZ-oSPu!itt>2&!3MqPfP5ChDSkFSH8F2WVOEf0(E_M(JL17G}Y+fg0_IuW%WQ
zG(mG&u<d$HDGTG--N>?|->YSdk0;8rc{yw2@2Z&GA}z{Wb91Ooz9VhA{b2DYE7RmG
zjL}?eq#iX%3#k;JWMx_{^2nNax`xPhByFiDX+a7uTGU|otOvIAUy|dEKkXOm-`aWS
z27pUzD{a)Ct<6p{{3)+lq@i`t@%>-wT4r?*S}k)58e09WZYP<FHdyPA5JO8{8|?N+
zqi)hNvlO*O+|i6<gw!<~F3i}+9jB!I_Y=QmeihA(%{U8hIJ^d63fk~TuH^2PD`=;e
s-wR!xNH1D_BdsZ;*`*lFn)Mmo0|Ng&v#M4dp#T5?07*qoM6N<$g6nFR7XSbN

literal 0
HcmV?d00001

diff --git a/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..8953cba09064923c5daf2d37e7c3c836ccdd794b
GIT binary patch
literal 1226
zcmV;*1U37KP)<h;3K|Lk000e1NJLTq005W(005W>0{{R3FC5Sl00039P)t-s|Ns9~
z#rP?<_5oL$Q^olD{r_0T`27C={r>*`|Nj71npVa5OTzc(_WfbW_({R{p56NV{r*M2
z_xt?)2V0#0Ns<IwoaFZYD7E$gOO&$Z{I}-(M!@%1kG%Q&{X2ZIEw}bv$M_ep_9e9S
z0acfN)A=K`_9(RUPs8^>fV0u>{42ctGP(8vQj-Btk1n|O0ZD=YLwd&R{Ko41Gr9H=
zY@z@@bOAMB5Ltl$E>bJJ{>JP30ZxkmI%?eW{k`b?Wy<&gOo;dS`~CR$Vwb@XWtR|N
zi~t=w02?-0&j0TD{>bb6sNwsK*!p?V`RMQUl(*DVjk-9Cx+-z1KXab|Ka2oXhX5f%
z`$|e!000AhNkl<Zc-rlk>rxs)5QTeTVRi&#7Emz~MKK1WAjCw(c-JK6eox;2O)?`?
zTG`AHia671e^vgmp!llKp|=5sVHk#C7=~epA~VAf-~%aPC=%Qw01h8mnSZ|p?hz91
z7p83F3%LVu9;S$tSI$C^%^yud1dfTM_6p2|+5Ejp$bd`GD<tQoa;#(tdg*x)^b%Ba
zB<dx&U)Pai49>vbR|xit>i!ZD&F>@CJrPmu*UjD&?DfZs=$@e3FQA(vNiU+$A*%a}
z?`XcG2jDxJ_ZQ#Md`H{4Lpf6QBDp81_KWZ6Tk#yCy1)32zO#3<7>b`eT7UyYH1eGz
z;O(rH$=QR*L%%ZcBpc=eGua?N55nD^K(8<#gl2+pN_j~b2MHs4#mcLmv%DkspS-3<
zpI1F=^9siI0s-;IN_IrA;5xm~3?3!StX}pUv0vkxMaqm+zxrg7X7(I&*N~&dEd0kD
z-FRV|g=|QuUsuh>-xCI}vD2imzYIOIdcCVV=$Bz@*u0+Bs<|L^)32nN*=wu3n%Ynw
z@1|eLG>!8ruU1pFXUfb`j>(=Gy~?Rn4QJ-c3%3T|(Frd!bI`9u&zAnyFYTqlG#&J7
zAkD(jpw|oZLNiA>;><E14vb!C<}61v(|=|!?3p_+{3UDZS8`^UqXVSX3uorc3rX$?
zgBj-N6r7jA4EKZs%)L+cEbx+}6e`CWdL?HT)GI#bCEzgCo0rk-&7lV`DdA{&!{YV0
zy887LPQW<=GWV7@&0eYX=i7@5umH{x5G^fN%Vw|k%=BW>hgp1KX7-wxC~31II47gc
zHcehD6Uxlf%+M^^uN5Wc*G%^;>D5qT{>=uxUhX%WJu^Z*(_Wq9y}npFO{Hhb>s6<9
zNi0pHXWFaVZnb)1+RS&F)xOv6&aeILcI)`k#0YE+?e)5&#r7J#c`3Z7x!LpTc01dx
zrdC3{Z;joZ^KN&))zB_i)I9fWedoN>Zl-6_Iz+^G&*ak2j<V8PXoPq(E5hmbxe_*B
zL8NCzkZaSWt6DUAR)k2Ir6){c{?c5yFzaVYs%JejB}TAkwwd{RZb~T9PxHo^dE6RA
z&7_)HtjuOCl;+mJu^Fa0XQT1s+b4*@8EAHL_T{0Cv$f9<fqUW+UgMUy7!LtFAtQ~9
o<N)eleSl#YhG7_nVQw400riWbnCg0%WB>pF07*qoM6N<$f;w%0(f|Me

literal 0
HcmV?d00001

diff --git a/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/frontend/app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..0467bf12aa4d28f374bb26596605a46dcbb3e7c8
GIT binary patch
literal 1418
zcmV;51$Fv~P)<h;3K|Lk000e1NJLTq005@|005^50{{R3L&&_|0002<P)t-s|Ns9~
z#rP?<_5oL$Q^ffF{{Q^_{`&p@SjPDK{{L6T_)f$3M8Ed{N|OOrnTpr?P{a5HTAk4D
z`~z5={{R2(`ToW0{7S+1UdZ?uu=R4G$LIF_V#@f2t<FZk_b#~h^7{VK@BE3@`mW>q
zKfU)WzW*n(@|xWGCA9ScMt*e9`2kdxPQ&<!ug?KelLAhO12k6wP>&>|-UCa7_51w+
zLUsW@ZzZSW0y$)Hp~e9%PvP|a03ks1`~K?q{u;6NC8*{AOqIUq{CL&;p56Lf$oQGq
z^={4hPQv)y=I|4n+?>7Fim=dxt<Pzk!)BSn06mMNcYMVF00dG=L_t(|+U?wHQxh>1
z2H+Dm+1+fh+IF>G0SjJMkQQre1x4|G*Z==(Ot&kCnUrL4I(rf(ucITwmuHf^hXiJT
zkdTm&kdTm&kdTm&kdP`esgWG0BcWCVkVZ&2dUwN`cgM8QJb`Z7Z~e<&Yj2(}>Tmf`
zm1{eLgw!b{bXkjWbF%dTkTZEJWyWOb##Lfw4EK2}<0d6%>AGS{po>WCOy&f$Tay_>
z?NBlkpo@s-O;0V%Y_Xa-G#_O08q5LR*~F%&)}{}r&L%Sbs8AS4t7Y0N<jX*!Zo1T)
zt|ujDdNPm_Uj|b5at$QXrYAL;&a;w9ef8K&nK>Ex*{soY=0MZExqA5XHQkqi#4gW3
zqODM^iyZl;dvf)-bOXtOru(s)Uc7~BFx{w-FK;2{`VA?(g&@3z&bfLFyctOH!cVsF
z7IL=fo-qBndRUm;kAdXR4e6>k-z|21AaN%ubeVrHl*<|s&Ax@W-t?LR(P-24A5=>a
z*R9#QvjzF8n%@1Nw@?CG@6(%>+-0ASK~jEmCV|&a*7-GKT72W<(TbSjf)&Eme6nGE
z>Gkj4Sq&2e+-G%|+NM8OOm5zVl9{Z8Dd8A5z3y8mZ=4Bv4%>as_{9cN#bm~;h>62(
zdqY93Zy}v&c4n($Vv!Uy<K_zKOlD+qWUdUFpAY5dH@%6osjq0CErn{#ykyp^kOXJ|
zicCq>bR8<y)-%R+rrz||Wzz|mSSH5JR}UOW%{1K(MW)nNGvf_6U5B!ao8CgILf1Aw
zG8(21)tipYTWdQR!P(SW&lOZ}Ix;uc9`9tF6EXD_)#ql#Ttg@c6QPVRxq2XT0i|SO
z>ocs7#zbfX1IY-*w~)p}XyZ-SFC~4w>BvMVr`dFbelV{lLL0bx7@*ZZdebr3`sP;?
zVImji)kG)(6Juv0lz@q`F!k1FE;CQ(D0iG$wchPbKZQELlsZ#~rt8#90Y_Xh&3U-<
z{s<&cCV_1`^TD^<AY&knfDgB9%(uhhCkR@o0C;q3ZPUygx3AnIhYBN9F~{R}6uAL?
za|+d%FUCc?y@1B}&Zmf!YDG=VT?Oq`P|6@wXBNfooEf<coiiu<`=wJs9XO-1ER)Wh
zOb-qgPDh|3$JQfrIvoy`(<!K^pvZhSn-$|zr!!DljVEM|CTE-_G;*y>ia9!*mQDq&
zn2{r`j};V|uV%_wsP!zB?m%;FeaRe+X47K0e+KE!8C{gAWF8)lCd1u1%~|M!XNRvw
zvtqy3iz0WSpWdhn6$hP8PaRBmp)q`#PCA`Vd#Tc$@f1tAcM>f_I@bC)hkI9|o(Iqv
zo}Piadq!j76}004RBio<`)70k^`K1NK)q>w?p^C6J2ZC!+UppiK6&y3Kmbv&O!oYF
z34$0Z;QO!JOY#!`qyGH<3Pd}Pt@q*A0V=3SVtWKRR8d8Z&@)3qLPA19LPA19LPEUC
YUoZo%k(ykuW&i*H07*qoM6N<$f+CH{y8r+H

literal 0
HcmV?d00001

diff --git a/frontend/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/frontend/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
new file mode 100644
index 0000000..0bedcf2
--- /dev/null
+++ b/frontend/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "idiom" : "universal",
+      "filename" : "LaunchImage.png",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "LaunchImage@2x.png",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "universal",
+      "filename" : "LaunchImage@3x.png",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
diff --git a/frontend/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/frontend/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
new file mode 100644
index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838
GIT binary patch
literal 68
zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J
Q1PU{Fy85}Sb4q9e0B4a5jsO4v

literal 0
HcmV?d00001

diff --git a/frontend/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/frontend/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
new file mode 100644
index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838
GIT binary patch
literal 68
zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J
Q1PU{Fy85}Sb4q9e0B4a5jsO4v

literal 0
HcmV?d00001

diff --git a/frontend/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/frontend/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
new file mode 100644
index 0000000000000000000000000000000000000000..9da19eacad3b03bb08bbddbbf4ac48dd78b3d838
GIT binary patch
literal 68
zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx0wlM}@Gt=>Zci7-kcv6Uzs@r-FtIZ-&5|)J
Q1PU{Fy85}Sb4q9e0B4a5jsO4v

literal 0
HcmV?d00001

diff --git a/frontend/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/frontend/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
new file mode 100644
index 0000000..89c2725
--- /dev/null
+++ b/frontend/app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md
@@ -0,0 +1,5 @@
+# Launch Screen Assets
+
+You can customize the launch screen with your own desired assets by replacing the image files in this directory.
+
+You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
\ No newline at end of file
diff --git a/frontend/app/ios/Runner/Base.lproj/LaunchScreen.storyboard b/frontend/app/ios/Runner/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 0000000..f2e259c
--- /dev/null
+++ b/frontend/app/ios/Runner/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
+    </dependencies>
+    <scenes>
+        <!--View Controller-->
+        <scene sceneID="EHf-IW-A2E">
+            <objects>
+                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
+                        <viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <subviews>
+                            <imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
+                            </imageView>
+                        </subviews>
+                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <constraints>
+                            <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
+                            <constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
+                        </constraints>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="53" y="375"/>
+        </scene>
+    </scenes>
+    <resources>
+        <image name="LaunchImage" width="168" height="185"/>
+    </resources>
+</document>
diff --git a/frontend/app/ios/Runner/Base.lproj/Main.storyboard b/frontend/app/ios/Runner/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..f3c2851
--- /dev/null
+++ b/frontend/app/ios/Runner/Base.lproj/Main.storyboard
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
+    </dependencies>
+    <scenes>
+        <!--Flutter View Controller-->
+        <scene sceneID="tne-QT-ifu">
+            <objects>
+                <viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
+                        <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
+                    </layoutGuides>
+                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+                        <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+            </objects>
+        </scene>
+    </scenes>
+</document>
diff --git a/frontend/app/ios/Runner/Info.plist b/frontend/app/ios/Runner/Info.plist
new file mode 100644
index 0000000..c2e05c5
--- /dev/null
+++ b/frontend/app/ios/Runner/Info.plist
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>$(DEVELOPMENT_LANGUAGE)</string>
+	<key>CFBundleDisplayName</key>
+	<string>App</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>app</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>$(FLUTTER_BUILD_NAME)</string>
+	<key>CFBundleSignature</key>
+	<string>????</string>
+	<key>CFBundleVersion</key>
+	<string>$(FLUTTER_BUILD_NUMBER)</string>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>UILaunchStoryboardName</key>
+	<string>LaunchScreen</string>
+	<key>UIMainStoryboardFile</key>
+	<string>Main</string>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>CADisableMinimumFrameDurationOnPhone</key>
+	<true/>
+	<key>UIApplicationSupportsIndirectInputEvents</key>
+	<true/>
+</dict>
+</plist>
diff --git a/frontend/app/ios/Runner/Runner-Bridging-Header.h b/frontend/app/ios/Runner/Runner-Bridging-Header.h
new file mode 100644
index 0000000..308a2a5
--- /dev/null
+++ b/frontend/app/ios/Runner/Runner-Bridging-Header.h
@@ -0,0 +1 @@
+#import "GeneratedPluginRegistrant.h"
diff --git a/frontend/app/ios/RunnerTests/RunnerTests.swift b/frontend/app/ios/RunnerTests/RunnerTests.swift
new file mode 100644
index 0000000..86a7c3b
--- /dev/null
+++ b/frontend/app/ios/RunnerTests/RunnerTests.swift
@@ -0,0 +1,12 @@
+import Flutter
+import UIKit
+import XCTest
+
+class RunnerTests: XCTestCase {
+
+  func testExample() {
+    // If you add code to the Runner application, consider adding tests here.
+    // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
+  }
+
+}
diff --git a/frontend/app/lib/gapi/client.dart b/frontend/app/lib/gapi/client.dart
new file mode 100644
index 0000000..8ffe047
--- /dev/null
+++ b/frontend/app/lib/gapi/client.dart
@@ -0,0 +1,45 @@
+import 'package:app/pb/rpc_login.pbserver.dart';
+
+import 'package:app/pb/service_df.pbserver.dart';
+
+import 'package:grpc/grpc.dart';
+
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'package:app/pb/service_df.pb.dart';
+
+class Client {
+  late dfApi stub;
+
+//  Future<void> main(List<String> args) async {
+//     final channel = ClientChannel('127.0.0.1',
+//         port: 8080,
+//         options:
+//             const ChannelOptions(credentials: ChannelCredentials.insecure()));
+//     stub = dfServiceBase(channel,
+//         options: CallOptions(timeout: Duration(seconds: 30)));
+//     // Run all of the demos in order.
+//     try {
+//       await runGetFeature();
+//       await runListFeatures();
+//       await runRecordRoute();
+//       await runRouteChat();
+//     } catch (e) {
+//       print('Caught error: $e');
+//     }
+//     await channel.shutdown();
+//   }
+  // Future<LoginResponse> login(
+  //     $pb.ServerContext ctx, LoginRequest request) async {}
+  // final channel = ClientChannel(
+  //   '127.0.0.1',
+  //   port: 9090,
+  //   options: const ChannelOptions(
+  //     credentials: ChannelCredentials.insecure(),
+  //   ),
+  // );
+
+  // dfApi stub = dfApi(
+  //   channel,
+  // );
+}
diff --git a/frontend/app/lib/main.dart b/frontend/app/lib/main.dart
new file mode 100644
index 0000000..697c294
--- /dev/null
+++ b/frontend/app/lib/main.dart
@@ -0,0 +1,7 @@
+import 'package:flutter/material.dart';
+
+import 'package:app/pages/main_screen.dart';
+
+void main() {
+  runApp(const MainScreen());
+}
diff --git a/frontend/app/lib/pages/main_screen.dart b/frontend/app/lib/pages/main_screen.dart
new file mode 100644
index 0000000..932bc0c
--- /dev/null
+++ b/frontend/app/lib/pages/main_screen.dart
@@ -0,0 +1,16 @@
+import 'package:flutter/material.dart';
+
+class MainScreen extends StatelessWidget {
+  const MainScreen({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return const Scaffold(
+      body: Column(
+        mainAxisAlignment: MainAxisAlignment.center,
+        crossAxisAlignment: CrossAxisAlignment.center,
+        children: [],
+      ),
+    );
+  }
+}
diff --git a/frontend/app/lib/pb/account.pb.dart b/frontend/app/lib/pb/account.pb.dart
new file mode 100644
index 0000000..dbf09e2
--- /dev/null
+++ b/frontend/app/lib/pb/account.pb.dart
@@ -0,0 +1,159 @@
+//
+//  Generated code. Do not modify.
+//  source: account.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'google/protobuf/timestamp.pb.dart' as $0;
+
+class Account extends $pb.GeneratedMessage {
+  factory Account({
+    $fixnum.Int64? id,
+    $core.String? email,
+    $core.String? secretKey,
+    $0.Timestamp? emailVerifiedTime,
+    $core.bool? emailVerified,
+    $0.Timestamp? privacyAcceptedDate,
+    $core.int? permissionLevel,
+  }) {
+    final $result = create();
+    if (id != null) {
+      $result.id = id;
+    }
+    if (email != null) {
+      $result.email = email;
+    }
+    if (secretKey != null) {
+      $result.secretKey = secretKey;
+    }
+    if (emailVerifiedTime != null) {
+      $result.emailVerifiedTime = emailVerifiedTime;
+    }
+    if (emailVerified != null) {
+      $result.emailVerified = emailVerified;
+    }
+    if (privacyAcceptedDate != null) {
+      $result.privacyAcceptedDate = privacyAcceptedDate;
+    }
+    if (permissionLevel != null) {
+      $result.permissionLevel = permissionLevel;
+    }
+    return $result;
+  }
+  Account._() : super();
+  factory Account.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory Account.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Account', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..aOS(2, _omitFieldNames ? '' : 'email')
+    ..aOS(3, _omitFieldNames ? '' : 'secretKey')
+    ..aOM<$0.Timestamp>(9, _omitFieldNames ? '' : 'emailVerifiedTime', subBuilder: $0.Timestamp.create)
+    ..aOB(10, _omitFieldNames ? '' : 'emailVerified')
+    ..aOM<$0.Timestamp>(12, _omitFieldNames ? '' : 'privacyAcceptedDate', subBuilder: $0.Timestamp.create)
+    ..a<$core.int>(13, _omitFieldNames ? '' : 'permissionLevel', $pb.PbFieldType.O3)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  Account clone() => Account()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  Account copyWith(void Function(Account) updates) => super.copyWith((message) => updates(message as Account)) as Account;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static Account create() => Account._();
+  Account createEmptyInstance() => create();
+  static $pb.PbList<Account> createRepeated() => $pb.PbList<Account>();
+  @$core.pragma('dart2js:noInline')
+  static Account getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Account>(create);
+  static Account? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get id => $_getI64(0);
+  @$pb.TagNumber(1)
+  set id($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.String get email => $_getSZ(1);
+  @$pb.TagNumber(2)
+  set email($core.String v) { $_setString(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasEmail() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearEmail() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $core.String get secretKey => $_getSZ(2);
+  @$pb.TagNumber(3)
+  set secretKey($core.String v) { $_setString(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasSecretKey() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearSecretKey() => clearField(3);
+
+  @$pb.TagNumber(9)
+  $0.Timestamp get emailVerifiedTime => $_getN(3);
+  @$pb.TagNumber(9)
+  set emailVerifiedTime($0.Timestamp v) { setField(9, v); }
+  @$pb.TagNumber(9)
+  $core.bool hasEmailVerifiedTime() => $_has(3);
+  @$pb.TagNumber(9)
+  void clearEmailVerifiedTime() => clearField(9);
+  @$pb.TagNumber(9)
+  $0.Timestamp ensureEmailVerifiedTime() => $_ensure(3);
+
+  @$pb.TagNumber(10)
+  $core.bool get emailVerified => $_getBF(4);
+  @$pb.TagNumber(10)
+  set emailVerified($core.bool v) { $_setBool(4, v); }
+  @$pb.TagNumber(10)
+  $core.bool hasEmailVerified() => $_has(4);
+  @$pb.TagNumber(10)
+  void clearEmailVerified() => clearField(10);
+
+  @$pb.TagNumber(12)
+  $0.Timestamp get privacyAcceptedDate => $_getN(5);
+  @$pb.TagNumber(12)
+  set privacyAcceptedDate($0.Timestamp v) { setField(12, v); }
+  @$pb.TagNumber(12)
+  $core.bool hasPrivacyAcceptedDate() => $_has(5);
+  @$pb.TagNumber(12)
+  void clearPrivacyAcceptedDate() => clearField(12);
+  @$pb.TagNumber(12)
+  $0.Timestamp ensurePrivacyAcceptedDate() => $_ensure(5);
+
+  @$pb.TagNumber(13)
+  $core.int get permissionLevel => $_getIZ(6);
+  @$pb.TagNumber(13)
+  set permissionLevel($core.int v) { $_setSignedInt32(6, v); }
+  @$pb.TagNumber(13)
+  $core.bool hasPermissionLevel() => $_has(6);
+  @$pb.TagNumber(13)
+  void clearPermissionLevel() => clearField(13);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/account.pbenum.dart b/frontend/app/lib/pb/account.pbenum.dart
new file mode 100644
index 0000000..3612eb7
--- /dev/null
+++ b/frontend/app/lib/pb/account.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: account.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/account.pbjson.dart b/frontend/app/lib/pb/account.pbjson.dart
new file mode 100644
index 0000000..0c3e1fb
--- /dev/null
+++ b/frontend/app/lib/pb/account.pbjson.dart
@@ -0,0 +1,52 @@
+//
+//  Generated code. Do not modify.
+//  source: account.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use accountDescriptor instead')
+const Account$json = {
+  '1': 'Account',
+  '2': [
+    {'1': 'id', '3': 1, '4': 1, '5': 4, '10': 'id'},
+    {'1': 'email', '3': 2, '4': 1, '5': 9, '10': 'email'},
+    {'1': 'secret_key', '3': 3, '4': 1, '5': 9, '9': 0, '10': 'secretKey', '17': true},
+    {'1': 'email_verified_time', '3': 9, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'emailVerifiedTime'},
+    {'1': 'email_verified', '3': 10, '4': 1, '5': 8, '10': 'emailVerified'},
+    {'1': 'privacy_accepted_date', '3': 12, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'privacyAcceptedDate'},
+    {'1': 'permission_level', '3': 13, '4': 1, '5': 5, '8': {}, '10': 'permissionLevel'},
+  ],
+  '7': {},
+  '8': [
+    {'1': '_secret_key'},
+  ],
+};
+
+/// Descriptor for `Account`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List accountDescriptor = $convert.base64Decode(
+    'CgdBY2NvdW50Eg4KAmlkGAEgASgEUgJpZBIUCgVlbWFpbBgCIAEoCVIFZW1haWwSIgoKc2Vjcm'
+    'V0X2tleRgDIAEoCUgAUglzZWNyZXRLZXmIAQESZwoTZW1haWxfdmVyaWZpZWRfdGltZRgJIAEo'
+    'CzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBCG5JBGEoWIjIwMjMtMTAtMDVUMDA6MDA6MD'
+    'BaIlIRZW1haWxWZXJpZmllZFRpbWUSJQoOZW1haWxfdmVyaWZpZWQYCiABKAhSDWVtYWlsVmVy'
+    'aWZpZWQSawoVcHJpdmFjeV9hY2NlcHRlZF9kYXRlGAwgASgLMhouZ29vZ2xlLnByb3RvYnVmLl'
+    'RpbWVzdGFtcEIbkkEYShYiMjAyMy0xMC0wNVQwMDowMDowMFoiUhNwcml2YWN5QWNjZXB0ZWRE'
+    'YXRlEk4KEHBlcm1pc3Npb25fbGV2ZWwYDSABKAVCI5JBIDIeRGVmYXVsdCBpcyAwIChub24tcH'
+    'JpdmlsZWRnZWQpUg9wZXJtaXNzaW9uTGV2ZWw6vQOSQbkDCgkqB0FjY291bnQyqwN7ImlkIjog'
+    'IjEiLCJlbWFpbCI6ICJqb2huLmRvZUBleGFtcGxlLmNvbSIsICJmaXJzdG5hbWUiOiAiSm9obi'
+    'IsICJsYXN0bmFtZSI6ICJEb2UiLCAicGhvbmUiOiAiIiwgInN0cmVldCI6ICJEZWF0aCBTdGFy'
+    'IDIiLCAiemlwIjogIjA4MTUiLCAiY2l0eSI6ICJOZXcgWW9yayIsICJjb3VudHJ5IjogIlVTQS'
+    'IsICJiaXJ0aGRheSI6ICIxOTkwLTEwLTA1VDAwOjAwOjAwWiIsICJwcml2YWN5X2FjY2VwdGVk'
+    'IjogZmFsc2UsICJwcml2YWN5X2FjY2VwdGVkX2RhdGUiOiAiMDAwMS0wMS0wMVQwMDowMDowMF'
+    'oiLCAiY3JlYXRvciI6ICJqb2huLmRvZUBleGFtcGxlLmNvbSIsICJjcmVhdGVkIjogIjIwMjMt'
+    'MTAtMDVUMDI6MzA6NTNaIiwgImNoYW5nZXIiOiAiam9obi5kb2VAZXhhbXBsZS5jb20iLCAiY2'
+    'hhbmdlZCI6ICIyMDIzLTEwLTA1VDAyOjMwOjUzWiJ9Qg0KC19zZWNyZXRfa2V5');
+
diff --git a/frontend/app/lib/pb/account.pbserver.dart b/frontend/app/lib/pb/account.pbserver.dart
new file mode 100644
index 0000000..50774a9
--- /dev/null
+++ b/frontend/app/lib/pb/account.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: account.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'account.pb.dart';
+
diff --git a/frontend/app/lib/pb/account_info.pb.dart b/frontend/app/lib/pb/account_info.pb.dart
new file mode 100644
index 0000000..38089b9
--- /dev/null
+++ b/frontend/app/lib/pb/account_info.pb.dart
@@ -0,0 +1,289 @@
+//
+//  Generated code. Do not modify.
+//  source: account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'google/protobuf/timestamp.pb.dart' as $0;
+
+class AccountInfo extends $pb.GeneratedMessage {
+  factory AccountInfo({
+    $fixnum.Int64? accountId,
+    $core.String? firstname,
+    $core.String? lastname,
+    $core.String? street,
+    $core.String? city,
+    $core.String? zip,
+    $core.String? country,
+    $0.Timestamp? birthday,
+    $core.String? phone,
+    $core.bool? privacyAccepted,
+    $0.Timestamp? privacyAcceptedDate,
+    $core.int? permissionLevel,
+    $core.String? creator,
+    $0.Timestamp? created,
+    $core.String? changer,
+    $0.Timestamp? changed,
+  }) {
+    final $result = create();
+    if (accountId != null) {
+      $result.accountId = accountId;
+    }
+    if (firstname != null) {
+      $result.firstname = firstname;
+    }
+    if (lastname != null) {
+      $result.lastname = lastname;
+    }
+    if (street != null) {
+      $result.street = street;
+    }
+    if (city != null) {
+      $result.city = city;
+    }
+    if (zip != null) {
+      $result.zip = zip;
+    }
+    if (country != null) {
+      $result.country = country;
+    }
+    if (birthday != null) {
+      $result.birthday = birthday;
+    }
+    if (phone != null) {
+      $result.phone = phone;
+    }
+    if (privacyAccepted != null) {
+      $result.privacyAccepted = privacyAccepted;
+    }
+    if (privacyAcceptedDate != null) {
+      $result.privacyAcceptedDate = privacyAcceptedDate;
+    }
+    if (permissionLevel != null) {
+      $result.permissionLevel = permissionLevel;
+    }
+    if (creator != null) {
+      $result.creator = creator;
+    }
+    if (created != null) {
+      $result.created = created;
+    }
+    if (changer != null) {
+      $result.changer = changer;
+    }
+    if (changed != null) {
+      $result.changed = changed;
+    }
+    return $result;
+  }
+  AccountInfo._() : super();
+  factory AccountInfo.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory AccountInfo.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'AccountInfo', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'accountId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..aOS(3, _omitFieldNames ? '' : 'firstname')
+    ..aOS(4, _omitFieldNames ? '' : 'lastname')
+    ..aOS(5, _omitFieldNames ? '' : 'street')
+    ..aOS(6, _omitFieldNames ? '' : 'city')
+    ..aOS(7, _omitFieldNames ? '' : 'zip')
+    ..aOS(8, _omitFieldNames ? '' : 'country')
+    ..aOM<$0.Timestamp>(9, _omitFieldNames ? '' : 'birthday', subBuilder: $0.Timestamp.create)
+    ..aOS(10, _omitFieldNames ? '' : 'phone')
+    ..aOB(11, _omitFieldNames ? '' : 'privacyAccepted')
+    ..aOM<$0.Timestamp>(12, _omitFieldNames ? '' : 'privacyAcceptedDate', subBuilder: $0.Timestamp.create)
+    ..a<$core.int>(13, _omitFieldNames ? '' : 'permissionLevel', $pb.PbFieldType.O3)
+    ..aOS(14, _omitFieldNames ? '' : 'creator')
+    ..aOM<$0.Timestamp>(15, _omitFieldNames ? '' : 'created', subBuilder: $0.Timestamp.create)
+    ..aOS(16, _omitFieldNames ? '' : 'changer')
+    ..aOM<$0.Timestamp>(17, _omitFieldNames ? '' : 'changed', subBuilder: $0.Timestamp.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  AccountInfo clone() => AccountInfo()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  AccountInfo copyWith(void Function(AccountInfo) updates) => super.copyWith((message) => updates(message as AccountInfo)) as AccountInfo;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static AccountInfo create() => AccountInfo._();
+  AccountInfo createEmptyInstance() => create();
+  static $pb.PbList<AccountInfo> createRepeated() => $pb.PbList<AccountInfo>();
+  @$core.pragma('dart2js:noInline')
+  static AccountInfo getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<AccountInfo>(create);
+  static AccountInfo? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get accountId => $_getI64(0);
+  @$pb.TagNumber(1)
+  set accountId($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccountId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccountId() => clearField(1);
+
+  @$pb.TagNumber(3)
+  $core.String get firstname => $_getSZ(1);
+  @$pb.TagNumber(3)
+  set firstname($core.String v) { $_setString(1, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasFirstname() => $_has(1);
+  @$pb.TagNumber(3)
+  void clearFirstname() => clearField(3);
+
+  @$pb.TagNumber(4)
+  $core.String get lastname => $_getSZ(2);
+  @$pb.TagNumber(4)
+  set lastname($core.String v) { $_setString(2, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasLastname() => $_has(2);
+  @$pb.TagNumber(4)
+  void clearLastname() => clearField(4);
+
+  @$pb.TagNumber(5)
+  $core.String get street => $_getSZ(3);
+  @$pb.TagNumber(5)
+  set street($core.String v) { $_setString(3, v); }
+  @$pb.TagNumber(5)
+  $core.bool hasStreet() => $_has(3);
+  @$pb.TagNumber(5)
+  void clearStreet() => clearField(5);
+
+  @$pb.TagNumber(6)
+  $core.String get city => $_getSZ(4);
+  @$pb.TagNumber(6)
+  set city($core.String v) { $_setString(4, v); }
+  @$pb.TagNumber(6)
+  $core.bool hasCity() => $_has(4);
+  @$pb.TagNumber(6)
+  void clearCity() => clearField(6);
+
+  @$pb.TagNumber(7)
+  $core.String get zip => $_getSZ(5);
+  @$pb.TagNumber(7)
+  set zip($core.String v) { $_setString(5, v); }
+  @$pb.TagNumber(7)
+  $core.bool hasZip() => $_has(5);
+  @$pb.TagNumber(7)
+  void clearZip() => clearField(7);
+
+  @$pb.TagNumber(8)
+  $core.String get country => $_getSZ(6);
+  @$pb.TagNumber(8)
+  set country($core.String v) { $_setString(6, v); }
+  @$pb.TagNumber(8)
+  $core.bool hasCountry() => $_has(6);
+  @$pb.TagNumber(8)
+  void clearCountry() => clearField(8);
+
+  @$pb.TagNumber(9)
+  $0.Timestamp get birthday => $_getN(7);
+  @$pb.TagNumber(9)
+  set birthday($0.Timestamp v) { setField(9, v); }
+  @$pb.TagNumber(9)
+  $core.bool hasBirthday() => $_has(7);
+  @$pb.TagNumber(9)
+  void clearBirthday() => clearField(9);
+  @$pb.TagNumber(9)
+  $0.Timestamp ensureBirthday() => $_ensure(7);
+
+  @$pb.TagNumber(10)
+  $core.String get phone => $_getSZ(8);
+  @$pb.TagNumber(10)
+  set phone($core.String v) { $_setString(8, v); }
+  @$pb.TagNumber(10)
+  $core.bool hasPhone() => $_has(8);
+  @$pb.TagNumber(10)
+  void clearPhone() => clearField(10);
+
+  @$pb.TagNumber(11)
+  $core.bool get privacyAccepted => $_getBF(9);
+  @$pb.TagNumber(11)
+  set privacyAccepted($core.bool v) { $_setBool(9, v); }
+  @$pb.TagNumber(11)
+  $core.bool hasPrivacyAccepted() => $_has(9);
+  @$pb.TagNumber(11)
+  void clearPrivacyAccepted() => clearField(11);
+
+  @$pb.TagNumber(12)
+  $0.Timestamp get privacyAcceptedDate => $_getN(10);
+  @$pb.TagNumber(12)
+  set privacyAcceptedDate($0.Timestamp v) { setField(12, v); }
+  @$pb.TagNumber(12)
+  $core.bool hasPrivacyAcceptedDate() => $_has(10);
+  @$pb.TagNumber(12)
+  void clearPrivacyAcceptedDate() => clearField(12);
+  @$pb.TagNumber(12)
+  $0.Timestamp ensurePrivacyAcceptedDate() => $_ensure(10);
+
+  @$pb.TagNumber(13)
+  $core.int get permissionLevel => $_getIZ(11);
+  @$pb.TagNumber(13)
+  set permissionLevel($core.int v) { $_setSignedInt32(11, v); }
+  @$pb.TagNumber(13)
+  $core.bool hasPermissionLevel() => $_has(11);
+  @$pb.TagNumber(13)
+  void clearPermissionLevel() => clearField(13);
+
+  @$pb.TagNumber(14)
+  $core.String get creator => $_getSZ(12);
+  @$pb.TagNumber(14)
+  set creator($core.String v) { $_setString(12, v); }
+  @$pb.TagNumber(14)
+  $core.bool hasCreator() => $_has(12);
+  @$pb.TagNumber(14)
+  void clearCreator() => clearField(14);
+
+  @$pb.TagNumber(15)
+  $0.Timestamp get created => $_getN(13);
+  @$pb.TagNumber(15)
+  set created($0.Timestamp v) { setField(15, v); }
+  @$pb.TagNumber(15)
+  $core.bool hasCreated() => $_has(13);
+  @$pb.TagNumber(15)
+  void clearCreated() => clearField(15);
+  @$pb.TagNumber(15)
+  $0.Timestamp ensureCreated() => $_ensure(13);
+
+  @$pb.TagNumber(16)
+  $core.String get changer => $_getSZ(14);
+  @$pb.TagNumber(16)
+  set changer($core.String v) { $_setString(14, v); }
+  @$pb.TagNumber(16)
+  $core.bool hasChanger() => $_has(14);
+  @$pb.TagNumber(16)
+  void clearChanger() => clearField(16);
+
+  @$pb.TagNumber(17)
+  $0.Timestamp get changed => $_getN(15);
+  @$pb.TagNumber(17)
+  set changed($0.Timestamp v) { setField(17, v); }
+  @$pb.TagNumber(17)
+  $core.bool hasChanged() => $_has(15);
+  @$pb.TagNumber(17)
+  void clearChanged() => clearField(17);
+  @$pb.TagNumber(17)
+  $0.Timestamp ensureChanged() => $_ensure(15);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/account_info.pbenum.dart b/frontend/app/lib/pb/account_info.pbenum.dart
new file mode 100644
index 0000000..70cea58
--- /dev/null
+++ b/frontend/app/lib/pb/account_info.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/account_info.pbjson.dart b/frontend/app/lib/pb/account_info.pbjson.dart
new file mode 100644
index 0000000..79b0e54
--- /dev/null
+++ b/frontend/app/lib/pb/account_info.pbjson.dart
@@ -0,0 +1,64 @@
+//
+//  Generated code. Do not modify.
+//  source: account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use accountInfoDescriptor instead')
+const AccountInfo$json = {
+  '1': 'AccountInfo',
+  '2': [
+    {'1': 'account_id', '3': 1, '4': 1, '5': 4, '10': 'accountId'},
+    {'1': 'firstname', '3': 3, '4': 1, '5': 9, '10': 'firstname'},
+    {'1': 'lastname', '3': 4, '4': 1, '5': 9, '10': 'lastname'},
+    {'1': 'street', '3': 5, '4': 1, '5': 9, '10': 'street'},
+    {'1': 'city', '3': 6, '4': 1, '5': 9, '10': 'city'},
+    {'1': 'zip', '3': 7, '4': 1, '5': 9, '10': 'zip'},
+    {'1': 'country', '3': 8, '4': 1, '5': 9, '10': 'country'},
+    {'1': 'birthday', '3': 9, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'birthday'},
+    {'1': 'phone', '3': 10, '4': 1, '5': 9, '10': 'phone'},
+    {'1': 'privacy_accepted', '3': 11, '4': 1, '5': 8, '10': 'privacyAccepted'},
+    {'1': 'privacy_accepted_date', '3': 12, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'privacyAcceptedDate'},
+    {'1': 'permission_level', '3': 13, '4': 1, '5': 5, '8': {}, '10': 'permissionLevel'},
+    {'1': 'creator', '3': 14, '4': 1, '5': 9, '10': 'creator'},
+    {'1': 'created', '3': 15, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'created'},
+    {'1': 'changer', '3': 16, '4': 1, '5': 9, '10': 'changer'},
+    {'1': 'changed', '3': 17, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'changed'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `AccountInfo`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List accountInfoDescriptor = $convert.base64Decode(
+    'CgtBY2NvdW50SW5mbxIdCgphY2NvdW50X2lkGAEgASgEUglhY2NvdW50SWQSHAoJZmlyc3RuYW'
+    '1lGAMgASgJUglmaXJzdG5hbWUSGgoIbGFzdG5hbWUYBCABKAlSCGxhc3RuYW1lEhYKBnN0cmVl'
+    'dBgFIAEoCVIGc3RyZWV0EhIKBGNpdHkYBiABKAlSBGNpdHkSEAoDemlwGAcgASgJUgN6aXASGA'
+    'oHY291bnRyeRgIIAEoCVIHY291bnRyeRJTCghiaXJ0aGRheRgJIAEoCzIaLmdvb2dsZS5wcm90'
+    'b2J1Zi5UaW1lc3RhbXBCG5JBGEoWIjE5OTAtMTAtMDVUMDA6MDA6MDBaIlIIYmlydGhkYXkSFA'
+    'oFcGhvbmUYCiABKAlSBXBob25lEikKEHByaXZhY3lfYWNjZXB0ZWQYCyABKAhSD3ByaXZhY3lB'
+    'Y2NlcHRlZBJrChVwcml2YWN5X2FjY2VwdGVkX2RhdGUYDCABKAsyGi5nb29nbGUucHJvdG9idW'
+    'YuVGltZXN0YW1wQhuSQRhKFiIyMDIzLTEwLTA1VDAwOjAwOjAwWiJSE3ByaXZhY3lBY2NlcHRl'
+    'ZERhdGUSTgoQcGVybWlzc2lvbl9sZXZlbBgNIAEoBUIjkkEgMh5EZWZhdWx0IGlzIDAgKG5vbi'
+    '1wcml2aWxlZGdlZClSD3Blcm1pc3Npb25MZXZlbBIYCgdjcmVhdG9yGA4gASgJUgdjcmVhdG9y'
+    'ElEKB2NyZWF0ZWQYDyABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wQhuSQRhKFiIyMD'
+    'IzLTEwLTA1VDAwOjAwOjAwWiJSB2NyZWF0ZWQSGAoHY2hhbmdlchgQIAEoCVIHY2hhbmdlchJR'
+    'CgdjaGFuZ2VkGBEgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcEIbkkEYShYiMjAyMy'
+    '0xMC0wNVQwMDowMDowMFoiUgdjaGFuZ2VkOqkDkkGlAwoNKgtBY2NvdW50SW5mbzKTA3siYWNj'
+    'b3VudF9pZCI6ICIxIiwgImZpcnN0bmFtZSI6ICJKb2huIiwgImxhc3RuYW1lIjogIkRvZSIsIC'
+    'JwaG9uZSI6ICIiLCAic3RyZWV0IjogIkRlYXRoIFN0YXIgMiIsICJ6aXAiOiAiMDgxNSIsICJj'
+    'aXR5IjogIk5ldyBZb3JrIiwgImNvdW50cnkiOiAiVVNBIiwgImJpcnRoZGF5IjogIjE5OTAtMT'
+    'AtMDVUMDA6MDA6MDBaIiwgInByaXZhY3lfYWNjZXB0ZWQiOiBmYWxzZSwgInByaXZhY3lfYWNj'
+    'ZXB0ZWRfZGF0ZSI6ICIwMDAxLTAxLTAxVDAwOjAwOjAwWiIsICJjcmVhdG9yIjogImpvaG4uZG'
+    '9lQGV4YW1wbGUuY29tIiwgImNyZWF0ZWQiOiAiMjAyMy0xMC0wNVQwMjozMDo1M1oiLCAiY2hh'
+    'bmdlciI6ICJqb2huLmRvZUBleGFtcGxlLmNvbSIsICJjaGFuZ2VkIjogIjIwMjMtMTAtMDVUMD'
+    'I6MzA6NTNaIn0=');
+
diff --git a/frontend/app/lib/pb/account_info.pbserver.dart b/frontend/app/lib/pb/account_info.pbserver.dart
new file mode 100644
index 0000000..0f19252
--- /dev/null
+++ b/frontend/app/lib/pb/account_info.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'account_info.pb.dart';
+
diff --git a/frontend/app/lib/pb/document.pb.dart b/frontend/app/lib/pb/document.pb.dart
new file mode 100644
index 0000000..3aa549b
--- /dev/null
+++ b/frontend/app/lib/pb/document.pb.dart
@@ -0,0 +1,259 @@
+//
+//  Generated code. Do not modify.
+//  source: document.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'google/protobuf/timestamp.pb.dart' as $0;
+
+class Document extends $pb.GeneratedMessage {
+  factory Document({
+    $fixnum.Int64? personId,
+    $fixnum.Int64? mailId,
+    $core.String? name,
+    $core.String? type,
+    $core.String? path,
+    $core.String? url,
+    $core.bool? valid,
+    $core.String? validatedBy,
+    $0.Timestamp? validDate,
+    $core.String? creator,
+    $0.Timestamp? created,
+    $core.String? changer,
+    $0.Timestamp? changed,
+    $fixnum.Int64? id,
+  }) {
+    final $result = create();
+    if (personId != null) {
+      $result.personId = personId;
+    }
+    if (mailId != null) {
+      $result.mailId = mailId;
+    }
+    if (name != null) {
+      $result.name = name;
+    }
+    if (type != null) {
+      $result.type = type;
+    }
+    if (path != null) {
+      $result.path = path;
+    }
+    if (url != null) {
+      $result.url = url;
+    }
+    if (valid != null) {
+      $result.valid = valid;
+    }
+    if (validatedBy != null) {
+      $result.validatedBy = validatedBy;
+    }
+    if (validDate != null) {
+      $result.validDate = validDate;
+    }
+    if (creator != null) {
+      $result.creator = creator;
+    }
+    if (created != null) {
+      $result.created = created;
+    }
+    if (changer != null) {
+      $result.changer = changer;
+    }
+    if (changed != null) {
+      $result.changed = changed;
+    }
+    if (id != null) {
+      $result.id = id;
+    }
+    return $result;
+  }
+  Document._() : super();
+  factory Document.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory Document.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Document', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'personId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..a<$fixnum.Int64>(2, _omitFieldNames ? '' : 'mailId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..aOS(3, _omitFieldNames ? '' : 'name')
+    ..aOS(4, _omitFieldNames ? '' : 'type')
+    ..aOS(5, _omitFieldNames ? '' : 'path')
+    ..aOS(6, _omitFieldNames ? '' : 'url')
+    ..aOB(7, _omitFieldNames ? '' : 'valid')
+    ..aOS(8, _omitFieldNames ? '' : 'validatedBy')
+    ..aOM<$0.Timestamp>(9, _omitFieldNames ? '' : 'validDate', subBuilder: $0.Timestamp.create)
+    ..aOS(10, _omitFieldNames ? '' : 'creator')
+    ..aOM<$0.Timestamp>(11, _omitFieldNames ? '' : 'created', subBuilder: $0.Timestamp.create)
+    ..aOS(12, _omitFieldNames ? '' : 'changer')
+    ..aOM<$0.Timestamp>(13, _omitFieldNames ? '' : 'changed', subBuilder: $0.Timestamp.create)
+    ..a<$fixnum.Int64>(14, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  Document clone() => Document()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  Document copyWith(void Function(Document) updates) => super.copyWith((message) => updates(message as Document)) as Document;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static Document create() => Document._();
+  Document createEmptyInstance() => create();
+  static $pb.PbList<Document> createRepeated() => $pb.PbList<Document>();
+  @$core.pragma('dart2js:noInline')
+  static Document getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Document>(create);
+  static Document? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get personId => $_getI64(0);
+  @$pb.TagNumber(1)
+  set personId($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasPersonId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearPersonId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $fixnum.Int64 get mailId => $_getI64(1);
+  @$pb.TagNumber(2)
+  set mailId($fixnum.Int64 v) { $_setInt64(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasMailId() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearMailId() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $core.String get name => $_getSZ(2);
+  @$pb.TagNumber(3)
+  set name($core.String v) { $_setString(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasName() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearName() => clearField(3);
+
+  @$pb.TagNumber(4)
+  $core.String get type => $_getSZ(3);
+  @$pb.TagNumber(4)
+  set type($core.String v) { $_setString(3, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasType() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearType() => clearField(4);
+
+  @$pb.TagNumber(5)
+  $core.String get path => $_getSZ(4);
+  @$pb.TagNumber(5)
+  set path($core.String v) { $_setString(4, v); }
+  @$pb.TagNumber(5)
+  $core.bool hasPath() => $_has(4);
+  @$pb.TagNumber(5)
+  void clearPath() => clearField(5);
+
+  @$pb.TagNumber(6)
+  $core.String get url => $_getSZ(5);
+  @$pb.TagNumber(6)
+  set url($core.String v) { $_setString(5, v); }
+  @$pb.TagNumber(6)
+  $core.bool hasUrl() => $_has(5);
+  @$pb.TagNumber(6)
+  void clearUrl() => clearField(6);
+
+  @$pb.TagNumber(7)
+  $core.bool get valid => $_getBF(6);
+  @$pb.TagNumber(7)
+  set valid($core.bool v) { $_setBool(6, v); }
+  @$pb.TagNumber(7)
+  $core.bool hasValid() => $_has(6);
+  @$pb.TagNumber(7)
+  void clearValid() => clearField(7);
+
+  @$pb.TagNumber(8)
+  $core.String get validatedBy => $_getSZ(7);
+  @$pb.TagNumber(8)
+  set validatedBy($core.String v) { $_setString(7, v); }
+  @$pb.TagNumber(8)
+  $core.bool hasValidatedBy() => $_has(7);
+  @$pb.TagNumber(8)
+  void clearValidatedBy() => clearField(8);
+
+  @$pb.TagNumber(9)
+  $0.Timestamp get validDate => $_getN(8);
+  @$pb.TagNumber(9)
+  set validDate($0.Timestamp v) { setField(9, v); }
+  @$pb.TagNumber(9)
+  $core.bool hasValidDate() => $_has(8);
+  @$pb.TagNumber(9)
+  void clearValidDate() => clearField(9);
+  @$pb.TagNumber(9)
+  $0.Timestamp ensureValidDate() => $_ensure(8);
+
+  @$pb.TagNumber(10)
+  $core.String get creator => $_getSZ(9);
+  @$pb.TagNumber(10)
+  set creator($core.String v) { $_setString(9, v); }
+  @$pb.TagNumber(10)
+  $core.bool hasCreator() => $_has(9);
+  @$pb.TagNumber(10)
+  void clearCreator() => clearField(10);
+
+  @$pb.TagNumber(11)
+  $0.Timestamp get created => $_getN(10);
+  @$pb.TagNumber(11)
+  set created($0.Timestamp v) { setField(11, v); }
+  @$pb.TagNumber(11)
+  $core.bool hasCreated() => $_has(10);
+  @$pb.TagNumber(11)
+  void clearCreated() => clearField(11);
+  @$pb.TagNumber(11)
+  $0.Timestamp ensureCreated() => $_ensure(10);
+
+  @$pb.TagNumber(12)
+  $core.String get changer => $_getSZ(11);
+  @$pb.TagNumber(12)
+  set changer($core.String v) { $_setString(11, v); }
+  @$pb.TagNumber(12)
+  $core.bool hasChanger() => $_has(11);
+  @$pb.TagNumber(12)
+  void clearChanger() => clearField(12);
+
+  @$pb.TagNumber(13)
+  $0.Timestamp get changed => $_getN(12);
+  @$pb.TagNumber(13)
+  set changed($0.Timestamp v) { setField(13, v); }
+  @$pb.TagNumber(13)
+  $core.bool hasChanged() => $_has(12);
+  @$pb.TagNumber(13)
+  void clearChanged() => clearField(13);
+  @$pb.TagNumber(13)
+  $0.Timestamp ensureChanged() => $_ensure(12);
+
+  @$pb.TagNumber(14)
+  $fixnum.Int64 get id => $_getI64(13);
+  @$pb.TagNumber(14)
+  set id($fixnum.Int64 v) { $_setInt64(13, v); }
+  @$pb.TagNumber(14)
+  $core.bool hasId() => $_has(13);
+  @$pb.TagNumber(14)
+  void clearId() => clearField(14);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/document.pbenum.dart b/frontend/app/lib/pb/document.pbenum.dart
new file mode 100644
index 0000000..64c9c9d
--- /dev/null
+++ b/frontend/app/lib/pb/document.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: document.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/document.pbjson.dart b/frontend/app/lib/pb/document.pbjson.dart
new file mode 100644
index 0000000..98d8737
--- /dev/null
+++ b/frontend/app/lib/pb/document.pbjson.dart
@@ -0,0 +1,55 @@
+//
+//  Generated code. Do not modify.
+//  source: document.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use documentDescriptor instead')
+const Document$json = {
+  '1': 'Document',
+  '2': [
+    {'1': 'person_id', '3': 1, '4': 1, '5': 4, '9': 0, '10': 'personId', '17': true},
+    {'1': 'mail_id', '3': 2, '4': 1, '5': 4, '9': 1, '10': 'mailId', '17': true},
+    {'1': 'name', '3': 3, '4': 1, '5': 9, '10': 'name'},
+    {'1': 'type', '3': 4, '4': 1, '5': 9, '10': 'type'},
+    {'1': 'path', '3': 5, '4': 1, '5': 9, '10': 'path'},
+    {'1': 'url', '3': 6, '4': 1, '5': 9, '10': 'url'},
+    {'1': 'valid', '3': 7, '4': 1, '5': 8, '10': 'valid'},
+    {'1': 'validated_by', '3': 8, '4': 1, '5': 9, '10': 'validatedBy'},
+    {'1': 'valid_date', '3': 9, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'validDate'},
+    {'1': 'creator', '3': 10, '4': 1, '5': 9, '10': 'creator'},
+    {'1': 'created', '3': 11, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'created'},
+    {'1': 'changer', '3': 12, '4': 1, '5': 9, '10': 'changer'},
+    {'1': 'changed', '3': 13, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'changed'},
+    {'1': 'id', '3': 14, '4': 1, '5': 4, '10': 'id'},
+  ],
+  '7': {},
+  '8': [
+    {'1': '_person_id'},
+    {'1': '_mail_id'},
+  ],
+};
+
+/// Descriptor for `Document`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List documentDescriptor = $convert.base64Decode(
+    'CghEb2N1bWVudBIgCglwZXJzb25faWQYASABKARIAFIIcGVyc29uSWSIAQESHAoHbWFpbF9pZB'
+    'gCIAEoBEgBUgZtYWlsSWSIAQESEgoEbmFtZRgDIAEoCVIEbmFtZRISCgR0eXBlGAQgASgJUgR0'
+    'eXBlEhIKBHBhdGgYBSABKAlSBHBhdGgSEAoDdXJsGAYgASgJUgN1cmwSFAoFdmFsaWQYByABKA'
+    'hSBXZhbGlkEiEKDHZhbGlkYXRlZF9ieRgIIAEoCVILdmFsaWRhdGVkQnkSVgoKdmFsaWRfZGF0'
+    'ZRgJIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBCG5JBGEoWIjIwMjMtMTAtMDVUMD'
+    'A6MDA6MDBaIlIJdmFsaWREYXRlEhgKB2NyZWF0b3IYCiABKAlSB2NyZWF0b3ISUQoHY3JlYXRl'
+    'ZBgLIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBCG5JBGEoWIjIwMjMtMTAtMDVUMD'
+    'A6MDA6MDBaIlIHY3JlYXRlZBIYCgdjaGFuZ2VyGAwgASgJUgdjaGFuZ2VyElEKB2NoYW5nZWQY'
+    'DSABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wQhuSQRhKFiIyMDIzLTEwLTA1VDAwOj'
+    'AwOjAwWiJSB2NoYW5nZWQSDgoCaWQYDiABKARSAmlkOg+SQQwKCioIRG9jdW1lbnRCDAoKX3Bl'
+    'cnNvbl9pZEIKCghfbWFpbF9pZA==');
+
diff --git a/frontend/app/lib/pb/document.pbserver.dart b/frontend/app/lib/pb/document.pbserver.dart
new file mode 100644
index 0000000..532039c
--- /dev/null
+++ b/frontend/app/lib/pb/document.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: document.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'document.pb.dart';
+
diff --git a/frontend/app/lib/pb/google/protobuf/timestamp.pb.dart b/frontend/app/lib/pb/google/protobuf/timestamp.pb.dart
new file mode 100644
index 0000000..dc49c14
--- /dev/null
+++ b/frontend/app/lib/pb/google/protobuf/timestamp.pb.dart
@@ -0,0 +1,188 @@
+//
+//  Generated code. Do not modify.
+//  source: timestamp.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+import 'package:protobuf/src/protobuf/mixins/well_known.dart' as $mixin;
+
+///  A Timestamp represents a point in time independent of any time zone or local
+///  calendar, encoded as a count of seconds and fractions of seconds at
+///  nanosecond resolution. The count is relative to an epoch at UTC midnight on
+///  January 1, 1970, in the proleptic Gregorian calendar which extends the
+///  Gregorian calendar backwards to year one.
+///
+///  All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap
+///  second table is needed for interpretation, using a [24-hour linear
+///  smear](https://developers.google.com/time/smear).
+///
+///  The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By
+///  restricting to that range, we ensure that we can convert to and from [RFC
+///  3339](https://www.ietf.org/rfc/rfc3339.txt) date strings.
+///
+///  # Examples
+///
+///  Example 1: Compute Timestamp from POSIX `time()`.
+///
+///      Timestamp timestamp;
+///      timestamp.set_seconds(time(NULL));
+///      timestamp.set_nanos(0);
+///
+///  Example 2: Compute Timestamp from POSIX `gettimeofday()`.
+///
+///      struct timeval tv;
+///      gettimeofday(&tv, NULL);
+///
+///      Timestamp timestamp;
+///      timestamp.set_seconds(tv.tv_sec);
+///      timestamp.set_nanos(tv.tv_usec * 1000);
+///
+///  Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
+///
+///      FILETIME ft;
+///      GetSystemTimeAsFileTime(&ft);
+///      UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
+///
+///      // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
+///      // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
+///      Timestamp timestamp;
+///      timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
+///      timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
+///
+///  Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
+///
+///      long millis = System.currentTimeMillis();
+///
+///      Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
+///          .setNanos((int) ((millis % 1000) * 1000000)).build();
+///
+///  Example 5: Compute Timestamp from Java `Instant.now()`.
+///
+///      Instant now = Instant.now();
+///
+///      Timestamp timestamp =
+///          Timestamp.newBuilder().setSeconds(now.getEpochSecond())
+///              .setNanos(now.getNano()).build();
+///
+///  Example 6: Compute Timestamp from current time in Python.
+///
+///      timestamp = Timestamp()
+///      timestamp.GetCurrentTime()
+///
+///  # JSON Mapping
+///
+///  In JSON format, the Timestamp type is encoded as a string in the
+///  [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
+///  format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
+///  where {year} is always expressed using four digits while {month}, {day},
+///  {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
+///  seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
+///  are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
+///  is required. A proto3 JSON serializer should always use UTC (as indicated by
+///  "Z") when printing the Timestamp type and a proto3 JSON parser should be
+///  able to accept both UTC and other timezones (as indicated by an offset).
+///
+///  For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
+///  01:30 UTC on January 15, 2017.
+///
+///  In JavaScript, one can convert a Date object to this format using the
+///  standard
+///  [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
+///  method. In Python, a standard `datetime.datetime` object can be converted
+///  to this format using
+///  [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with
+///  the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use
+///  the Joda Time's [`ISODateTimeFormat.dateTime()`](
+///  http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()
+///  ) to obtain a formatter capable of generating timestamps in this format.
+class Timestamp extends $pb.GeneratedMessage with $mixin.TimestampMixin {
+  factory Timestamp({
+    $fixnum.Int64? seconds,
+    $core.int? nanos,
+  }) {
+    final $result = create();
+    if (seconds != null) {
+      $result.seconds = seconds;
+    }
+    if (nanos != null) {
+      $result.nanos = nanos;
+    }
+    return $result;
+  }
+  Timestamp._() : super();
+  factory Timestamp.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory Timestamp.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Timestamp', package: const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'), createEmptyInstance: create, toProto3Json: $mixin.TimestampMixin.toProto3JsonHelper, fromProto3Json: $mixin.TimestampMixin.fromProto3JsonHelper)
+    ..aInt64(1, _omitFieldNames ? '' : 'seconds')
+    ..a<$core.int>(2, _omitFieldNames ? '' : 'nanos', $pb.PbFieldType.O3)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  Timestamp clone() => Timestamp()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  Timestamp copyWith(void Function(Timestamp) updates) => super.copyWith((message) => updates(message as Timestamp)) as Timestamp;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static Timestamp create() => Timestamp._();
+  Timestamp createEmptyInstance() => create();
+  static $pb.PbList<Timestamp> createRepeated() => $pb.PbList<Timestamp>();
+  @$core.pragma('dart2js:noInline')
+  static Timestamp getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Timestamp>(create);
+  static Timestamp? _defaultInstance;
+
+  /// Represents seconds of UTC time since Unix epoch
+  /// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
+  /// 9999-12-31T23:59:59Z inclusive.
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get seconds => $_getI64(0);
+  @$pb.TagNumber(1)
+  set seconds($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasSeconds() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearSeconds() => clearField(1);
+
+  /// Non-negative fractions of a second at nanosecond resolution. Negative
+  /// second values with fractions must still have non-negative nanos values
+  /// that count forward in time. Must be from 0 to 999,999,999
+  /// inclusive.
+  @$pb.TagNumber(2)
+  $core.int get nanos => $_getIZ(1);
+  @$pb.TagNumber(2)
+  set nanos($core.int v) { $_setSignedInt32(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasNanos() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearNanos() => clearField(2);
+  /// Creates a new instance from [dateTime].
+  ///
+  /// Time zone information will not be preserved.
+  static Timestamp fromDateTime($core.DateTime dateTime) {
+    final result = create();
+    $mixin.TimestampMixin.setFromDateTime(result, dateTime);
+    return result;
+  }
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/google/protobuf/timestamp.pbenum.dart b/frontend/app/lib/pb/google/protobuf/timestamp.pbenum.dart
new file mode 100644
index 0000000..d77b416
--- /dev/null
+++ b/frontend/app/lib/pb/google/protobuf/timestamp.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: timestamp.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/google/protobuf/timestamp.pbjson.dart b/frontend/app/lib/pb/google/protobuf/timestamp.pbjson.dart
new file mode 100644
index 0000000..0af4c77
--- /dev/null
+++ b/frontend/app/lib/pb/google/protobuf/timestamp.pbjson.dart
@@ -0,0 +1,29 @@
+//
+//  Generated code. Do not modify.
+//  source: timestamp.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use timestampDescriptor instead')
+const Timestamp$json = {
+  '1': 'Timestamp',
+  '2': [
+    {'1': 'seconds', '3': 1, '4': 1, '5': 3, '10': 'seconds'},
+    {'1': 'nanos', '3': 2, '4': 1, '5': 5, '10': 'nanos'},
+  ],
+};
+
+/// Descriptor for `Timestamp`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List timestampDescriptor = $convert.base64Decode(
+    'CglUaW1lc3RhbXASGAoHc2Vjb25kcxgBIAEoA1IHc2Vjb25kcxIUCgVuYW5vcxgCIAEoBVIFbm'
+    'Fub3M=');
+
diff --git a/frontend/app/lib/pb/google/protobuf/timestamp.proto b/frontend/app/lib/pb/google/protobuf/timestamp.proto
new file mode 100644
index 0000000..d0698db
--- /dev/null
+++ b/frontend/app/lib/pb/google/protobuf/timestamp.proto
@@ -0,0 +1,144 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package google.protobuf;
+
+option cc_enable_arenas = true;
+option go_package = "google.golang.org/protobuf/types/known/timestamppb";
+option java_package = "com.google.protobuf";
+option java_outer_classname = "TimestampProto";
+option java_multiple_files = true;
+option objc_class_prefix = "GPB";
+option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+
+// A Timestamp represents a point in time independent of any time zone or local
+// calendar, encoded as a count of seconds and fractions of seconds at
+// nanosecond resolution. The count is relative to an epoch at UTC midnight on
+// January 1, 1970, in the proleptic Gregorian calendar which extends the
+// Gregorian calendar backwards to year one.
+//
+// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap
+// second table is needed for interpretation, using a [24-hour linear
+// smear](https://developers.google.com/time/smear).
+//
+// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By
+// restricting to that range, we ensure that we can convert to and from [RFC
+// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings.
+//
+// # Examples
+//
+// Example 1: Compute Timestamp from POSIX `time()`.
+//
+//     Timestamp timestamp;
+//     timestamp.set_seconds(time(NULL));
+//     timestamp.set_nanos(0);
+//
+// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
+//
+//     struct timeval tv;
+//     gettimeofday(&tv, NULL);
+//
+//     Timestamp timestamp;
+//     timestamp.set_seconds(tv.tv_sec);
+//     timestamp.set_nanos(tv.tv_usec * 1000);
+//
+// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
+//
+//     FILETIME ft;
+//     GetSystemTimeAsFileTime(&ft);
+//     UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
+//
+//     // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
+//     // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
+//     Timestamp timestamp;
+//     timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
+//     timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
+//
+// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
+//
+//     long millis = System.currentTimeMillis();
+//
+//     Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
+//         .setNanos((int) ((millis % 1000) * 1000000)).build();
+//
+// Example 5: Compute Timestamp from Java `Instant.now()`.
+//
+//     Instant now = Instant.now();
+//
+//     Timestamp timestamp =
+//         Timestamp.newBuilder().setSeconds(now.getEpochSecond())
+//             .setNanos(now.getNano()).build();
+//
+// Example 6: Compute Timestamp from current time in Python.
+//
+//     timestamp = Timestamp()
+//     timestamp.GetCurrentTime()
+//
+// # JSON Mapping
+//
+// In JSON format, the Timestamp type is encoded as a string in the
+// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
+// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
+// where {year} is always expressed using four digits while {month}, {day},
+// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
+// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
+// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
+// is required. A proto3 JSON serializer should always use UTC (as indicated by
+// "Z") when printing the Timestamp type and a proto3 JSON parser should be
+// able to accept both UTC and other timezones (as indicated by an offset).
+//
+// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
+// 01:30 UTC on January 15, 2017.
+//
+// In JavaScript, one can convert a Date object to this format using the
+// standard
+// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
+// method. In Python, a standard `datetime.datetime` object can be converted
+// to this format using
+// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with
+// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use
+// the Joda Time's [`ISODateTimeFormat.dateTime()`](
+// http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()
+// ) to obtain a formatter capable of generating timestamps in this format.
+//
+message Timestamp {
+  // Represents seconds of UTC time since Unix epoch
+  // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
+  // 9999-12-31T23:59:59Z inclusive.
+  int64 seconds = 1;
+
+  // Non-negative fractions of a second at nanosecond resolution. Negative
+  // second values with fractions must still have non-negative nanos values
+  // that count forward in time. Must be from 0 to 999,999,999
+  // inclusive.
+  int32 nanos = 2;
+}
\ No newline at end of file
diff --git a/frontend/app/lib/pb/payment.pb.dart b/frontend/app/lib/pb/payment.pb.dart
new file mode 100644
index 0000000..29a550b
--- /dev/null
+++ b/frontend/app/lib/pb/payment.pb.dart
@@ -0,0 +1,257 @@
+//
+//  Generated code. Do not modify.
+//  source: payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'google/protobuf/timestamp.pb.dart' as $0;
+
+class Payment extends $pb.GeneratedMessage {
+  factory Payment({
+    $fixnum.Int64? id,
+    $fixnum.Int64? accountId,
+    $core.String? paymentCategory,
+    $core.String? bankname,
+    $core.String? iBAN,
+    $core.String? bIC,
+    $core.String? paypalAccount,
+    $core.String? paypalId,
+    $core.String? paymentSystem,
+    $core.String? type,
+    $core.String? creator,
+    $0.Timestamp? created,
+    $core.String? changer,
+    $0.Timestamp? changed,
+  }) {
+    final $result = create();
+    if (id != null) {
+      $result.id = id;
+    }
+    if (accountId != null) {
+      $result.accountId = accountId;
+    }
+    if (paymentCategory != null) {
+      $result.paymentCategory = paymentCategory;
+    }
+    if (bankname != null) {
+      $result.bankname = bankname;
+    }
+    if (iBAN != null) {
+      $result.iBAN = iBAN;
+    }
+    if (bIC != null) {
+      $result.bIC = bIC;
+    }
+    if (paypalAccount != null) {
+      $result.paypalAccount = paypalAccount;
+    }
+    if (paypalId != null) {
+      $result.paypalId = paypalId;
+    }
+    if (paymentSystem != null) {
+      $result.paymentSystem = paymentSystem;
+    }
+    if (type != null) {
+      $result.type = type;
+    }
+    if (creator != null) {
+      $result.creator = creator;
+    }
+    if (created != null) {
+      $result.created = created;
+    }
+    if (changer != null) {
+      $result.changer = changer;
+    }
+    if (changed != null) {
+      $result.changed = changed;
+    }
+    return $result;
+  }
+  Payment._() : super();
+  factory Payment.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory Payment.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Payment', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..a<$fixnum.Int64>(2, _omitFieldNames ? '' : 'accountId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..aOS(3, _omitFieldNames ? '' : 'paymentCategory')
+    ..aOS(4, _omitFieldNames ? '' : 'bankname')
+    ..aOS(5, _omitFieldNames ? '' : 'IBAN', protoName: 'IBAN')
+    ..aOS(6, _omitFieldNames ? '' : 'BIC', protoName: 'BIC')
+    ..aOS(7, _omitFieldNames ? '' : 'paypalAccount')
+    ..aOS(8, _omitFieldNames ? '' : 'paypalId')
+    ..aOS(9, _omitFieldNames ? '' : 'paymentSystem')
+    ..aOS(10, _omitFieldNames ? '' : 'type')
+    ..aOS(11, _omitFieldNames ? '' : 'creator')
+    ..aOM<$0.Timestamp>(12, _omitFieldNames ? '' : 'created', subBuilder: $0.Timestamp.create)
+    ..aOS(13, _omitFieldNames ? '' : 'changer')
+    ..aOM<$0.Timestamp>(14, _omitFieldNames ? '' : 'changed', subBuilder: $0.Timestamp.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  Payment clone() => Payment()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  Payment copyWith(void Function(Payment) updates) => super.copyWith((message) => updates(message as Payment)) as Payment;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static Payment create() => Payment._();
+  Payment createEmptyInstance() => create();
+  static $pb.PbList<Payment> createRepeated() => $pb.PbList<Payment>();
+  @$core.pragma('dart2js:noInline')
+  static Payment getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Payment>(create);
+  static Payment? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get id => $_getI64(0);
+  @$pb.TagNumber(1)
+  set id($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $fixnum.Int64 get accountId => $_getI64(1);
+  @$pb.TagNumber(2)
+  set accountId($fixnum.Int64 v) { $_setInt64(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasAccountId() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearAccountId() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $core.String get paymentCategory => $_getSZ(2);
+  @$pb.TagNumber(3)
+  set paymentCategory($core.String v) { $_setString(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasPaymentCategory() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearPaymentCategory() => clearField(3);
+
+  @$pb.TagNumber(4)
+  $core.String get bankname => $_getSZ(3);
+  @$pb.TagNumber(4)
+  set bankname($core.String v) { $_setString(3, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasBankname() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearBankname() => clearField(4);
+
+  @$pb.TagNumber(5)
+  $core.String get iBAN => $_getSZ(4);
+  @$pb.TagNumber(5)
+  set iBAN($core.String v) { $_setString(4, v); }
+  @$pb.TagNumber(5)
+  $core.bool hasIBAN() => $_has(4);
+  @$pb.TagNumber(5)
+  void clearIBAN() => clearField(5);
+
+  @$pb.TagNumber(6)
+  $core.String get bIC => $_getSZ(5);
+  @$pb.TagNumber(6)
+  set bIC($core.String v) { $_setString(5, v); }
+  @$pb.TagNumber(6)
+  $core.bool hasBIC() => $_has(5);
+  @$pb.TagNumber(6)
+  void clearBIC() => clearField(6);
+
+  @$pb.TagNumber(7)
+  $core.String get paypalAccount => $_getSZ(6);
+  @$pb.TagNumber(7)
+  set paypalAccount($core.String v) { $_setString(6, v); }
+  @$pb.TagNumber(7)
+  $core.bool hasPaypalAccount() => $_has(6);
+  @$pb.TagNumber(7)
+  void clearPaypalAccount() => clearField(7);
+
+  @$pb.TagNumber(8)
+  $core.String get paypalId => $_getSZ(7);
+  @$pb.TagNumber(8)
+  set paypalId($core.String v) { $_setString(7, v); }
+  @$pb.TagNumber(8)
+  $core.bool hasPaypalId() => $_has(7);
+  @$pb.TagNumber(8)
+  void clearPaypalId() => clearField(8);
+
+  @$pb.TagNumber(9)
+  $core.String get paymentSystem => $_getSZ(8);
+  @$pb.TagNumber(9)
+  set paymentSystem($core.String v) { $_setString(8, v); }
+  @$pb.TagNumber(9)
+  $core.bool hasPaymentSystem() => $_has(8);
+  @$pb.TagNumber(9)
+  void clearPaymentSystem() => clearField(9);
+
+  @$pb.TagNumber(10)
+  $core.String get type => $_getSZ(9);
+  @$pb.TagNumber(10)
+  set type($core.String v) { $_setString(9, v); }
+  @$pb.TagNumber(10)
+  $core.bool hasType() => $_has(9);
+  @$pb.TagNumber(10)
+  void clearType() => clearField(10);
+
+  @$pb.TagNumber(11)
+  $core.String get creator => $_getSZ(10);
+  @$pb.TagNumber(11)
+  set creator($core.String v) { $_setString(10, v); }
+  @$pb.TagNumber(11)
+  $core.bool hasCreator() => $_has(10);
+  @$pb.TagNumber(11)
+  void clearCreator() => clearField(11);
+
+  @$pb.TagNumber(12)
+  $0.Timestamp get created => $_getN(11);
+  @$pb.TagNumber(12)
+  set created($0.Timestamp v) { setField(12, v); }
+  @$pb.TagNumber(12)
+  $core.bool hasCreated() => $_has(11);
+  @$pb.TagNumber(12)
+  void clearCreated() => clearField(12);
+  @$pb.TagNumber(12)
+  $0.Timestamp ensureCreated() => $_ensure(11);
+
+  @$pb.TagNumber(13)
+  $core.String get changer => $_getSZ(12);
+  @$pb.TagNumber(13)
+  set changer($core.String v) { $_setString(12, v); }
+  @$pb.TagNumber(13)
+  $core.bool hasChanger() => $_has(12);
+  @$pb.TagNumber(13)
+  void clearChanger() => clearField(13);
+
+  @$pb.TagNumber(14)
+  $0.Timestamp get changed => $_getN(13);
+  @$pb.TagNumber(14)
+  set changed($0.Timestamp v) { setField(14, v); }
+  @$pb.TagNumber(14)
+  $core.bool hasChanged() => $_has(13);
+  @$pb.TagNumber(14)
+  void clearChanged() => clearField(14);
+  @$pb.TagNumber(14)
+  $0.Timestamp ensureChanged() => $_ensure(13);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/payment.pbenum.dart b/frontend/app/lib/pb/payment.pbenum.dart
new file mode 100644
index 0000000..771e456
--- /dev/null
+++ b/frontend/app/lib/pb/payment.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/payment.pbjson.dart b/frontend/app/lib/pb/payment.pbjson.dart
new file mode 100644
index 0000000..8e66d40
--- /dev/null
+++ b/frontend/app/lib/pb/payment.pbjson.dart
@@ -0,0 +1,66 @@
+//
+//  Generated code. Do not modify.
+//  source: payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use paymentDescriptor instead')
+const Payment$json = {
+  '1': 'Payment',
+  '2': [
+    {'1': 'id', '3': 1, '4': 1, '5': 4, '10': 'id'},
+    {'1': 'account_id', '3': 2, '4': 1, '5': 4, '10': 'accountId'},
+    {'1': 'payment_category', '3': 3, '4': 1, '5': 9, '10': 'paymentCategory'},
+    {'1': 'bankname', '3': 4, '4': 1, '5': 9, '9': 0, '10': 'bankname', '17': true},
+    {'1': 'IBAN', '3': 5, '4': 1, '5': 9, '9': 1, '10': 'IBAN', '17': true},
+    {'1': 'BIC', '3': 6, '4': 1, '5': 9, '9': 2, '10': 'BIC', '17': true},
+    {'1': 'paypal_account', '3': 7, '4': 1, '5': 9, '9': 3, '10': 'paypalAccount', '17': true},
+    {'1': 'paypal_id', '3': 8, '4': 1, '5': 9, '9': 4, '10': 'paypalId', '17': true},
+    {'1': 'payment_system', '3': 9, '4': 1, '5': 9, '9': 5, '10': 'paymentSystem', '17': true},
+    {'1': 'type', '3': 10, '4': 1, '5': 9, '10': 'type'},
+    {'1': 'creator', '3': 11, '4': 1, '5': 9, '10': 'creator'},
+    {'1': 'created', '3': 12, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'created'},
+    {'1': 'changer', '3': 13, '4': 1, '5': 9, '10': 'changer'},
+    {'1': 'changed', '3': 14, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'changed'},
+  ],
+  '7': {},
+  '8': [
+    {'1': '_bankname'},
+    {'1': '_IBAN'},
+    {'1': '_BIC'},
+    {'1': '_paypal_account'},
+    {'1': '_paypal_id'},
+    {'1': '_payment_system'},
+  ],
+};
+
+/// Descriptor for `Payment`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List paymentDescriptor = $convert.base64Decode(
+    'CgdQYXltZW50Eg4KAmlkGAEgASgEUgJpZBIdCgphY2NvdW50X2lkGAIgASgEUglhY2NvdW50SW'
+    'QSKQoQcGF5bWVudF9jYXRlZ29yeRgDIAEoCVIPcGF5bWVudENhdGVnb3J5Eh8KCGJhbmtuYW1l'
+    'GAQgASgJSABSCGJhbmtuYW1liAEBEhcKBElCQU4YBSABKAlIAVIESUJBTogBARIVCgNCSUMYBi'
+    'ABKAlIAlIDQklDiAEBEioKDnBheXBhbF9hY2NvdW50GAcgASgJSANSDXBheXBhbEFjY291bnSI'
+    'AQESIAoJcGF5cGFsX2lkGAggASgJSARSCHBheXBhbElkiAEBEioKDnBheW1lbnRfc3lzdGVtGA'
+    'kgASgJSAVSDXBheW1lbnRTeXN0ZW2IAQESEgoEdHlwZRgKIAEoCVIEdHlwZRIYCgdjcmVhdG9y'
+    'GAsgASgJUgdjcmVhdG9yElEKB2NyZWF0ZWQYDCABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZX'
+    'N0YW1wQhuSQRhKFiIyMDIzLTEwLTA1VDAwOjAwOjAwWiJSB2NyZWF0ZWQSGAoHY2hhbmdlchgN'
+    'IAEoCVIHY2hhbmdlchJRCgdjaGFuZ2VkGA4gASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdG'
+    'FtcEIbkkEYShYiMjAyMy0xMC0wNVQwMDowMDowMFoiUgdjaGFuZ2VkOu4CkkHqAgoJKgdQYXlt'
+    'ZW50MtwCeyJpZCI6ICIxIiwiYWNjb3VudF9pZCI6ICIxIiwgInBheW1lbnRfY2F0ZWdvcnkiOi'
+    'AiVEJEOiBwYXlwYWwiLCAicGF5cGFsX2FjY291bnQiOiAiam9obi5kb2VAZXhhbXBsZS5jb20i'
+    'LCAicGF5cGFsX2lkIjogInRoaXMtaXMtYS1wYXlwYWwtaWQiLCAicGF5bWVudF9zeXN0ZW0iOi'
+    'AiVEJEOiBwYXlwYWwgc3lzdGVtIiwgInR5cGUiOiAiVEJEOiBzb21lIHR5cGUiLCAiY3JlYXRv'
+    'ciI6ICJqb2huLmRvZUBleGFtcGxlLmNvbSIsICJjcmVhdGVkIjogIjIwMjMtMTAtMDVUMDI6Mz'
+    'A6NTNaIiwgImNoYW5nZXIiOiAiam9obi5kb2VAZXhhbXBsZS5jb20iLCAiY2hhbmdlZCI6ICIy'
+    'MDIzLTEwLTA1VDAyOjMwOjUzWiJ9QgsKCV9iYW5rbmFtZUIHCgVfSUJBTkIGCgRfQklDQhEKD1'
+    '9wYXlwYWxfYWNjb3VudEIMCgpfcGF5cGFsX2lkQhEKD19wYXltZW50X3N5c3RlbQ==');
+
diff --git a/frontend/app/lib/pb/payment.pbserver.dart b/frontend/app/lib/pb/payment.pbserver.dart
new file mode 100644
index 0000000..da6b450
--- /dev/null
+++ b/frontend/app/lib/pb/payment.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'payment.pb.dart';
+
diff --git a/frontend/app/lib/pb/person.pb.dart b/frontend/app/lib/pb/person.pb.dart
new file mode 100644
index 0000000..62a8d88
--- /dev/null
+++ b/frontend/app/lib/pb/person.pb.dart
@@ -0,0 +1,245 @@
+//
+//  Generated code. Do not modify.
+//  source: person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'google/protobuf/timestamp.pb.dart' as $0;
+
+class Person extends $pb.GeneratedMessage {
+  factory Person({
+    $fixnum.Int64? id,
+    $fixnum.Int64? accountId,
+    $core.String? firstname,
+    $core.String? lastname,
+    $core.String? street,
+    $core.String? city,
+    $core.String? zip,
+    $core.String? country,
+    $0.Timestamp? birthday,
+    $core.String? creator,
+    $0.Timestamp? created,
+    $core.String? changer,
+    $0.Timestamp? changed,
+  }) {
+    final $result = create();
+    if (id != null) {
+      $result.id = id;
+    }
+    if (accountId != null) {
+      $result.accountId = accountId;
+    }
+    if (firstname != null) {
+      $result.firstname = firstname;
+    }
+    if (lastname != null) {
+      $result.lastname = lastname;
+    }
+    if (street != null) {
+      $result.street = street;
+    }
+    if (city != null) {
+      $result.city = city;
+    }
+    if (zip != null) {
+      $result.zip = zip;
+    }
+    if (country != null) {
+      $result.country = country;
+    }
+    if (birthday != null) {
+      $result.birthday = birthday;
+    }
+    if (creator != null) {
+      $result.creator = creator;
+    }
+    if (created != null) {
+      $result.created = created;
+    }
+    if (changer != null) {
+      $result.changer = changer;
+    }
+    if (changed != null) {
+      $result.changed = changed;
+    }
+    return $result;
+  }
+  Person._() : super();
+  factory Person.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory Person.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Person', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..a<$fixnum.Int64>(2, _omitFieldNames ? '' : 'accountId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..aOS(3, _omitFieldNames ? '' : 'firstname')
+    ..aOS(4, _omitFieldNames ? '' : 'lastname')
+    ..aOS(5, _omitFieldNames ? '' : 'street')
+    ..aOS(6, _omitFieldNames ? '' : 'city')
+    ..aOS(7, _omitFieldNames ? '' : 'zip')
+    ..aOS(8, _omitFieldNames ? '' : 'country')
+    ..aOM<$0.Timestamp>(9, _omitFieldNames ? '' : 'birthday', subBuilder: $0.Timestamp.create)
+    ..aOS(10, _omitFieldNames ? '' : 'creator')
+    ..aOM<$0.Timestamp>(11, _omitFieldNames ? '' : 'created', subBuilder: $0.Timestamp.create)
+    ..aOS(12, _omitFieldNames ? '' : 'changer')
+    ..aOM<$0.Timestamp>(13, _omitFieldNames ? '' : 'changed', subBuilder: $0.Timestamp.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  Person clone() => Person()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  Person copyWith(void Function(Person) updates) => super.copyWith((message) => updates(message as Person)) as Person;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static Person create() => Person._();
+  Person createEmptyInstance() => create();
+  static $pb.PbList<Person> createRepeated() => $pb.PbList<Person>();
+  @$core.pragma('dart2js:noInline')
+  static Person getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Person>(create);
+  static Person? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get id => $_getI64(0);
+  @$pb.TagNumber(1)
+  set id($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $fixnum.Int64 get accountId => $_getI64(1);
+  @$pb.TagNumber(2)
+  set accountId($fixnum.Int64 v) { $_setInt64(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasAccountId() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearAccountId() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $core.String get firstname => $_getSZ(2);
+  @$pb.TagNumber(3)
+  set firstname($core.String v) { $_setString(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasFirstname() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearFirstname() => clearField(3);
+
+  @$pb.TagNumber(4)
+  $core.String get lastname => $_getSZ(3);
+  @$pb.TagNumber(4)
+  set lastname($core.String v) { $_setString(3, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasLastname() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearLastname() => clearField(4);
+
+  @$pb.TagNumber(5)
+  $core.String get street => $_getSZ(4);
+  @$pb.TagNumber(5)
+  set street($core.String v) { $_setString(4, v); }
+  @$pb.TagNumber(5)
+  $core.bool hasStreet() => $_has(4);
+  @$pb.TagNumber(5)
+  void clearStreet() => clearField(5);
+
+  @$pb.TagNumber(6)
+  $core.String get city => $_getSZ(5);
+  @$pb.TagNumber(6)
+  set city($core.String v) { $_setString(5, v); }
+  @$pb.TagNumber(6)
+  $core.bool hasCity() => $_has(5);
+  @$pb.TagNumber(6)
+  void clearCity() => clearField(6);
+
+  @$pb.TagNumber(7)
+  $core.String get zip => $_getSZ(6);
+  @$pb.TagNumber(7)
+  set zip($core.String v) { $_setString(6, v); }
+  @$pb.TagNumber(7)
+  $core.bool hasZip() => $_has(6);
+  @$pb.TagNumber(7)
+  void clearZip() => clearField(7);
+
+  @$pb.TagNumber(8)
+  $core.String get country => $_getSZ(7);
+  @$pb.TagNumber(8)
+  set country($core.String v) { $_setString(7, v); }
+  @$pb.TagNumber(8)
+  $core.bool hasCountry() => $_has(7);
+  @$pb.TagNumber(8)
+  void clearCountry() => clearField(8);
+
+  @$pb.TagNumber(9)
+  $0.Timestamp get birthday => $_getN(8);
+  @$pb.TagNumber(9)
+  set birthday($0.Timestamp v) { setField(9, v); }
+  @$pb.TagNumber(9)
+  $core.bool hasBirthday() => $_has(8);
+  @$pb.TagNumber(9)
+  void clearBirthday() => clearField(9);
+  @$pb.TagNumber(9)
+  $0.Timestamp ensureBirthday() => $_ensure(8);
+
+  @$pb.TagNumber(10)
+  $core.String get creator => $_getSZ(9);
+  @$pb.TagNumber(10)
+  set creator($core.String v) { $_setString(9, v); }
+  @$pb.TagNumber(10)
+  $core.bool hasCreator() => $_has(9);
+  @$pb.TagNumber(10)
+  void clearCreator() => clearField(10);
+
+  @$pb.TagNumber(11)
+  $0.Timestamp get created => $_getN(10);
+  @$pb.TagNumber(11)
+  set created($0.Timestamp v) { setField(11, v); }
+  @$pb.TagNumber(11)
+  $core.bool hasCreated() => $_has(10);
+  @$pb.TagNumber(11)
+  void clearCreated() => clearField(11);
+  @$pb.TagNumber(11)
+  $0.Timestamp ensureCreated() => $_ensure(10);
+
+  @$pb.TagNumber(12)
+  $core.String get changer => $_getSZ(11);
+  @$pb.TagNumber(12)
+  set changer($core.String v) { $_setString(11, v); }
+  @$pb.TagNumber(12)
+  $core.bool hasChanger() => $_has(11);
+  @$pb.TagNumber(12)
+  void clearChanger() => clearField(12);
+
+  @$pb.TagNumber(13)
+  $0.Timestamp get changed => $_getN(12);
+  @$pb.TagNumber(13)
+  set changed($0.Timestamp v) { setField(13, v); }
+  @$pb.TagNumber(13)
+  $core.bool hasChanged() => $_has(12);
+  @$pb.TagNumber(13)
+  void clearChanged() => clearField(13);
+  @$pb.TagNumber(13)
+  $0.Timestamp ensureChanged() => $_ensure(12);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/person.pbenum.dart b/frontend/app/lib/pb/person.pbenum.dart
new file mode 100644
index 0000000..3d2a943
--- /dev/null
+++ b/frontend/app/lib/pb/person.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/person.pbjson.dart b/frontend/app/lib/pb/person.pbjson.dart
new file mode 100644
index 0000000..0594753
--- /dev/null
+++ b/frontend/app/lib/pb/person.pbjson.dart
@@ -0,0 +1,57 @@
+//
+//  Generated code. Do not modify.
+//  source: person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use personDescriptor instead')
+const Person$json = {
+  '1': 'Person',
+  '2': [
+    {'1': 'id', '3': 1, '4': 1, '5': 4, '10': 'id'},
+    {'1': 'account_id', '3': 2, '4': 1, '5': 4, '10': 'accountId'},
+    {'1': 'firstname', '3': 3, '4': 1, '5': 9, '10': 'firstname'},
+    {'1': 'lastname', '3': 4, '4': 1, '5': 9, '10': 'lastname'},
+    {'1': 'street', '3': 5, '4': 1, '5': 9, '10': 'street'},
+    {'1': 'city', '3': 6, '4': 1, '5': 9, '10': 'city'},
+    {'1': 'zip', '3': 7, '4': 1, '5': 9, '10': 'zip'},
+    {'1': 'country', '3': 8, '4': 1, '5': 9, '10': 'country'},
+    {'1': 'birthday', '3': 9, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'birthday'},
+    {'1': 'creator', '3': 10, '4': 1, '5': 9, '10': 'creator'},
+    {'1': 'created', '3': 11, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'created'},
+    {'1': 'changer', '3': 12, '4': 1, '5': 9, '10': 'changer'},
+    {'1': 'changed', '3': 13, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'changed'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `Person`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List personDescriptor = $convert.base64Decode(
+    'CgZQZXJzb24SDgoCaWQYASABKARSAmlkEh0KCmFjY291bnRfaWQYAiABKARSCWFjY291bnRJZB'
+    'IcCglmaXJzdG5hbWUYAyABKAlSCWZpcnN0bmFtZRIaCghsYXN0bmFtZRgEIAEoCVIIbGFzdG5h'
+    'bWUSFgoGc3RyZWV0GAUgASgJUgZzdHJlZXQSEgoEY2l0eRgGIAEoCVIEY2l0eRIQCgN6aXAYBy'
+    'ABKAlSA3ppcBIYCgdjb3VudHJ5GAggASgJUgdjb3VudHJ5ElMKCGJpcnRoZGF5GAkgASgLMhou'
+    'Z29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcEIbkkEYShYiMTk5MC0xMC0wNVQwMDowMDowMFoiUg'
+    'hiaXJ0aGRheRIYCgdjcmVhdG9yGAogASgJUgdjcmVhdG9yElEKB2NyZWF0ZWQYCyABKAsyGi5n'
+    'b29nbGUucHJvdG9idWYuVGltZXN0YW1wQhuSQRhKFiIyMDIzLTEwLTA1VDAwOjAwOjAwWiJSB2'
+    'NyZWF0ZWQSGAoHY2hhbmdlchgMIAEoCVIHY2hhbmdlchJRCgdjaGFuZ2VkGA0gASgLMhouZ29v'
+    'Z2xlLnByb3RvYnVmLlRpbWVzdGFtcEIbkkEYShYiMjAyMy0xMC0wNVQwMDowMDowMFoiUgdjaG'
+    'FuZ2VkOrwDkkG4AwoIKgZQZXJzb24yqwN7ImlkIjogIjEiLCJlbWFpbCI6ICJqb2huLmRvZUBl'
+    'eGFtcGxlLmNvbSIsICJmaXJzdG5hbWUiOiAiSm9obiIsICJsYXN0bmFtZSI6ICJEb2UiLCAicG'
+    'hvbmUiOiAiIiwgInN0cmVldCI6ICJEZWF0aCBTdGFyIDIiLCAiemlwIjogIjA4MTUiLCAiY2l0'
+    'eSI6ICJOZXcgWW9yayIsICJjb3VudHJ5IjogIlVTQSIsICJiaXJ0aGRheSI6ICIxOTkwLTEwLT'
+    'A1VDAwOjAwOjAwWiIsICJwcml2YWN5X2FjY2VwdGVkIjogZmFsc2UsICJwcml2YWN5X2FjY2Vw'
+    'dGVkX2RhdGUiOiAiMDAwMS0wMS0wMVQwMDowMDowMFoiLCAiY3JlYXRvciI6ICJqb2huLmRvZU'
+    'BleGFtcGxlLmNvbSIsICJjcmVhdGVkIjogIjIwMjMtMTAtMDVUMDI6MzA6NTNaIiwgImNoYW5n'
+    'ZXIiOiAiam9obi5kb2VAZXhhbXBsZS5jb20iLCAiY2hhbmdlZCI6ICIyMDIzLTEwLTA1VDAyOj'
+    'MwOjUzWiJ9');
+
diff --git a/frontend/app/lib/pb/person.pbserver.dart b/frontend/app/lib/pb/person.pbserver.dart
new file mode 100644
index 0000000..659fc7a
--- /dev/null
+++ b/frontend/app/lib/pb/person.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'person.pb.dart';
+
diff --git a/frontend/app/lib/pb/returns_log.pb.dart b/frontend/app/lib/pb/returns_log.pb.dart
new file mode 100644
index 0000000..d365d08
--- /dev/null
+++ b/frontend/app/lib/pb/returns_log.pb.dart
@@ -0,0 +1,173 @@
+//
+//  Generated code. Do not modify.
+//  source: returns_log.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'google/protobuf/timestamp.pb.dart' as $0;
+
+class ReturnsLog extends $pb.GeneratedMessage {
+  factory ReturnsLog({
+    $fixnum.Int64? id,
+    $fixnum.Int64? returnId,
+    $fixnum.Int64? mailId,
+    $core.String? status,
+    $core.String? creator,
+    $0.Timestamp? created,
+    $core.String? changer,
+    $0.Timestamp? changed,
+  }) {
+    final $result = create();
+    if (id != null) {
+      $result.id = id;
+    }
+    if (returnId != null) {
+      $result.returnId = returnId;
+    }
+    if (mailId != null) {
+      $result.mailId = mailId;
+    }
+    if (status != null) {
+      $result.status = status;
+    }
+    if (creator != null) {
+      $result.creator = creator;
+    }
+    if (created != null) {
+      $result.created = created;
+    }
+    if (changer != null) {
+      $result.changer = changer;
+    }
+    if (changed != null) {
+      $result.changed = changed;
+    }
+    return $result;
+  }
+  ReturnsLog._() : super();
+  factory ReturnsLog.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ReturnsLog.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ReturnsLog', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..a<$fixnum.Int64>(2, _omitFieldNames ? '' : 'returnId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'mailId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..aOS(4, _omitFieldNames ? '' : 'status')
+    ..aOS(5, _omitFieldNames ? '' : 'creator')
+    ..aOM<$0.Timestamp>(6, _omitFieldNames ? '' : 'created', subBuilder: $0.Timestamp.create)
+    ..aOS(7, _omitFieldNames ? '' : 'changer')
+    ..aOM<$0.Timestamp>(8, _omitFieldNames ? '' : 'changed', subBuilder: $0.Timestamp.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  ReturnsLog clone() => ReturnsLog()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ReturnsLog copyWith(void Function(ReturnsLog) updates) => super.copyWith((message) => updates(message as ReturnsLog)) as ReturnsLog;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static ReturnsLog create() => ReturnsLog._();
+  ReturnsLog createEmptyInstance() => create();
+  static $pb.PbList<ReturnsLog> createRepeated() => $pb.PbList<ReturnsLog>();
+  @$core.pragma('dart2js:noInline')
+  static ReturnsLog getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ReturnsLog>(create);
+  static ReturnsLog? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get id => $_getI64(0);
+  @$pb.TagNumber(1)
+  set id($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $fixnum.Int64 get returnId => $_getI64(1);
+  @$pb.TagNumber(2)
+  set returnId($fixnum.Int64 v) { $_setInt64(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasReturnId() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearReturnId() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $fixnum.Int64 get mailId => $_getI64(2);
+  @$pb.TagNumber(3)
+  set mailId($fixnum.Int64 v) { $_setInt64(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasMailId() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearMailId() => clearField(3);
+
+  @$pb.TagNumber(4)
+  $core.String get status => $_getSZ(3);
+  @$pb.TagNumber(4)
+  set status($core.String v) { $_setString(3, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasStatus() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearStatus() => clearField(4);
+
+  @$pb.TagNumber(5)
+  $core.String get creator => $_getSZ(4);
+  @$pb.TagNumber(5)
+  set creator($core.String v) { $_setString(4, v); }
+  @$pb.TagNumber(5)
+  $core.bool hasCreator() => $_has(4);
+  @$pb.TagNumber(5)
+  void clearCreator() => clearField(5);
+
+  @$pb.TagNumber(6)
+  $0.Timestamp get created => $_getN(5);
+  @$pb.TagNumber(6)
+  set created($0.Timestamp v) { setField(6, v); }
+  @$pb.TagNumber(6)
+  $core.bool hasCreated() => $_has(5);
+  @$pb.TagNumber(6)
+  void clearCreated() => clearField(6);
+  @$pb.TagNumber(6)
+  $0.Timestamp ensureCreated() => $_ensure(5);
+
+  @$pb.TagNumber(7)
+  $core.String get changer => $_getSZ(6);
+  @$pb.TagNumber(7)
+  set changer($core.String v) { $_setString(6, v); }
+  @$pb.TagNumber(7)
+  $core.bool hasChanger() => $_has(6);
+  @$pb.TagNumber(7)
+  void clearChanger() => clearField(7);
+
+  @$pb.TagNumber(8)
+  $0.Timestamp get changed => $_getN(7);
+  @$pb.TagNumber(8)
+  set changed($0.Timestamp v) { setField(8, v); }
+  @$pb.TagNumber(8)
+  $core.bool hasChanged() => $_has(7);
+  @$pb.TagNumber(8)
+  void clearChanged() => clearField(8);
+  @$pb.TagNumber(8)
+  $0.Timestamp ensureChanged() => $_ensure(7);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/returns_log.pbenum.dart b/frontend/app/lib/pb/returns_log.pbenum.dart
new file mode 100644
index 0000000..be0cc3e
--- /dev/null
+++ b/frontend/app/lib/pb/returns_log.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: returns_log.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/returns_log.pbjson.dart b/frontend/app/lib/pb/returns_log.pbjson.dart
new file mode 100644
index 0000000..6dda1c4
--- /dev/null
+++ b/frontend/app/lib/pb/returns_log.pbjson.dart
@@ -0,0 +1,48 @@
+//
+//  Generated code. Do not modify.
+//  source: returns_log.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use returnsLogDescriptor instead')
+const ReturnsLog$json = {
+  '1': 'ReturnsLog',
+  '2': [
+    {'1': 'id', '3': 1, '4': 1, '5': 4, '10': 'id'},
+    {'1': 'return_id', '3': 2, '4': 1, '5': 4, '10': 'returnId'},
+    {'1': 'mail_id', '3': 3, '4': 1, '5': 4, '10': 'mailId'},
+    {'1': 'status', '3': 4, '4': 1, '5': 9, '10': 'status'},
+    {'1': 'creator', '3': 5, '4': 1, '5': 9, '10': 'creator'},
+    {'1': 'created', '3': 6, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'created'},
+    {'1': 'changer', '3': 7, '4': 1, '5': 9, '10': 'changer'},
+    {'1': 'changed', '3': 8, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'changed'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `ReturnsLog`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List returnsLogDescriptor = $convert.base64Decode(
+    'CgpSZXR1cm5zTG9nEg4KAmlkGAEgASgEUgJpZBIbCglyZXR1cm5faWQYAiABKARSCHJldHVybk'
+    'lkEhcKB21haWxfaWQYAyABKARSBm1haWxJZBIWCgZzdGF0dXMYBCABKAlSBnN0YXR1cxIYCgdj'
+    'cmVhdG9yGAUgASgJUgdjcmVhdG9yElEKB2NyZWF0ZWQYBiABKAsyGi5nb29nbGUucHJvdG9idW'
+    'YuVGltZXN0YW1wQhuSQRhKFiIyMDIzLTEwLTA1VDAwOjAwOjAwWiJSB2NyZWF0ZWQSGAoHY2hh'
+    'bmdlchgHIAEoCVIHY2hhbmdlchJRCgdjaGFuZ2VkGAggASgLMhouZ29vZ2xlLnByb3RvYnVmLl'
+    'RpbWVzdGFtcEIbkkEYShYiMjAyMy0xMC0wNVQwMDowMDowMFoiUgdjaGFuZ2VkOsADkkG8AwoM'
+    'KgpSZXR1cm5zTG9nMqsDeyJpZCI6ICIxIiwiZW1haWwiOiAiam9obi5kb2VAZXhhbXBsZS5jb2'
+    '0iLCAiZmlyc3RuYW1lIjogIkpvaG4iLCAibGFzdG5hbWUiOiAiRG9lIiwgInBob25lIjogIiIs'
+    'ICJzdHJlZXQiOiAiRGVhdGggU3RhciAyIiwgInppcCI6ICIwODE1IiwgImNpdHkiOiAiTmV3IF'
+    'lvcmsiLCAiY291bnRyeSI6ICJVU0EiLCAiYmlydGhkYXkiOiAiMTk5MC0xMC0wNVQwMDowMDow'
+    'MFoiLCAicHJpdmFjeV9hY2NlcHRlZCI6IGZhbHNlLCAicHJpdmFjeV9hY2NlcHRlZF9kYXRlIj'
+    'ogIjAwMDEtMDEtMDFUMDA6MDA6MDBaIiwgImNyZWF0b3IiOiAiam9obi5kb2VAZXhhbXBsZS5j'
+    'b20iLCAiY3JlYXRlZCI6ICIyMDIzLTEwLTA1VDAyOjMwOjUzWiIsICJjaGFuZ2VyIjogImpvaG'
+    '4uZG9lQGV4YW1wbGUuY29tIiwgImNoYW5nZWQiOiAiMjAyMy0xMC0wNVQwMjozMDo1M1oifQ==');
+
diff --git a/frontend/app/lib/pb/returns_log.pbserver.dart b/frontend/app/lib/pb/returns_log.pbserver.dart
new file mode 100644
index 0000000..ca8149a
--- /dev/null
+++ b/frontend/app/lib/pb/returns_log.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: returns_log.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'returns_log.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_block_session.pb.dart b/frontend/app/lib/pb/rpc_block_session.pb.dart
new file mode 100644
index 0000000..e26c2a5
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_block_session.pb.dart
@@ -0,0 +1,132 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_block_session.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:protobuf/protobuf.dart' as $pb;
+
+class BlockSessionRequest extends $pb.GeneratedMessage {
+  factory BlockSessionRequest({
+    $core.String? sessionId,
+  }) {
+    final $result = create();
+    if (sessionId != null) {
+      $result.sessionId = sessionId;
+    }
+    return $result;
+  }
+  BlockSessionRequest._() : super();
+  factory BlockSessionRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory BlockSessionRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'BlockSessionRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOS(1, _omitFieldNames ? '' : 'sessionId')
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  BlockSessionRequest clone() => BlockSessionRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  BlockSessionRequest copyWith(void Function(BlockSessionRequest) updates) => super.copyWith((message) => updates(message as BlockSessionRequest)) as BlockSessionRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static BlockSessionRequest create() => BlockSessionRequest._();
+  BlockSessionRequest createEmptyInstance() => create();
+  static $pb.PbList<BlockSessionRequest> createRepeated() => $pb.PbList<BlockSessionRequest>();
+  @$core.pragma('dart2js:noInline')
+  static BlockSessionRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<BlockSessionRequest>(create);
+  static BlockSessionRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get sessionId => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set sessionId($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasSessionId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearSessionId() => clearField(1);
+}
+
+class BlockSessionResponse extends $pb.GeneratedMessage {
+  factory BlockSessionResponse({
+    $core.String? sessionId,
+    $core.bool? blocked,
+  }) {
+    final $result = create();
+    if (sessionId != null) {
+      $result.sessionId = sessionId;
+    }
+    if (blocked != null) {
+      $result.blocked = blocked;
+    }
+    return $result;
+  }
+  BlockSessionResponse._() : super();
+  factory BlockSessionResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory BlockSessionResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'BlockSessionResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOS(1, _omitFieldNames ? '' : 'sessionId')
+    ..aOB(2, _omitFieldNames ? '' : 'blocked')
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  BlockSessionResponse clone() => BlockSessionResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  BlockSessionResponse copyWith(void Function(BlockSessionResponse) updates) => super.copyWith((message) => updates(message as BlockSessionResponse)) as BlockSessionResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static BlockSessionResponse create() => BlockSessionResponse._();
+  BlockSessionResponse createEmptyInstance() => create();
+  static $pb.PbList<BlockSessionResponse> createRepeated() => $pb.PbList<BlockSessionResponse>();
+  @$core.pragma('dart2js:noInline')
+  static BlockSessionResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<BlockSessionResponse>(create);
+  static BlockSessionResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get sessionId => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set sessionId($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasSessionId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearSessionId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.bool get blocked => $_getBF(1);
+  @$pb.TagNumber(2)
+  set blocked($core.bool v) { $_setBool(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasBlocked() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearBlocked() => clearField(2);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_block_session.pbenum.dart b/frontend/app/lib/pb/rpc_block_session.pbenum.dart
new file mode 100644
index 0000000..aa684ed
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_block_session.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_block_session.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_block_session.pbjson.dart b/frontend/app/lib/pb/rpc_block_session.pbjson.dart
new file mode 100644
index 0000000..6c0074e
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_block_session.pbjson.dart
@@ -0,0 +1,49 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_block_session.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use blockSessionRequestDescriptor instead')
+const BlockSessionRequest$json = {
+  '1': 'BlockSessionRequest',
+  '2': [
+    {'1': 'session_id', '3': 1, '4': 1, '5': 9, '8': {}, '10': 'sessionId'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `BlockSessionRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List blockSessionRequestDescriptor = $convert.base64Decode(
+    'ChNCbG9ja1Nlc3Npb25SZXF1ZXN0ElEKCnNlc3Npb25faWQYASABKAlCMpJBL0omIjVlMWQ2N2'
+    'RhLTdjOWItNDM2NS1hNGQ1LTNjYzBhMDUxMjQxZSKiAgR1dWlkUglzZXNzaW9uSWQ6apJBZwot'
+    'Kg1CbG9jayBTZXNzaW9uMg9CbG9jayBhIFNlc3Npb27SAQpzZXNzaW9uX2lkMjZ7InNlc3Npb2'
+    '5faWQiOiAiNWUxZDY3ZGEtN2M5Yi00MzY1LWE0ZDUtM2NjMGEwNTEyNDFlIn0=');
+
+@$core.Deprecated('Use blockSessionResponseDescriptor instead')
+const BlockSessionResponse$json = {
+  '1': 'BlockSessionResponse',
+  '2': [
+    {'1': 'session_id', '3': 1, '4': 1, '5': 9, '8': {}, '10': 'sessionId'},
+    {'1': 'blocked', '3': 2, '4': 1, '5': 8, '8': {}, '10': 'blocked'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `BlockSessionResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List blockSessionResponseDescriptor = $convert.base64Decode(
+    'ChRCbG9ja1Nlc3Npb25SZXNwb25zZRJRCgpzZXNzaW9uX2lkGAEgASgJQjKSQS9KJiI1ZTFkNj'
+    'dkYS03YzliLTQzNjUtYTRkNS0zY2MwYTA1MTI0MWUiogIEdXVpZFIJc2Vzc2lvbklkEiMKB2Js'
+    'b2NrZWQYAiABKAhCCZJBBkoEdHJ1ZVIHYmxvY2tlZDpfkkFcChEqD0Jsb2NrZWQgU2Vzc2lvbj'
+    'JHeyJzZXNzaW9uX2lkIjogIjVlMWQ2N2RhLTdjOWItNDM2NS1hNGQ1LTNjYzBhMDUxMjQxZSIs'
+    'ICJibG9ja2VkIjogdHJ1ZX0=');
+
diff --git a/frontend/app/lib/pb/rpc_block_session.pbserver.dart b/frontend/app/lib/pb/rpc_block_session.pbserver.dart
new file mode 100644
index 0000000..57b2eee
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_block_session.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_block_session.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_block_session.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_create_account.pb.dart b/frontend/app/lib/pb/rpc_create_account.pb.dart
new file mode 100644
index 0000000..15e65df
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_create_account.pb.dart
@@ -0,0 +1,136 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_create_account.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'account.pb.dart' as $2;
+
+class CreateAccountRequest extends $pb.GeneratedMessage {
+  factory CreateAccountRequest({
+    $core.String? email,
+    $core.String? password,
+  }) {
+    final $result = create();
+    if (email != null) {
+      $result.email = email;
+    }
+    if (password != null) {
+      $result.password = password;
+    }
+    return $result;
+  }
+  CreateAccountRequest._() : super();
+  factory CreateAccountRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory CreateAccountRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CreateAccountRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOS(1, _omitFieldNames ? '' : 'email')
+    ..aOS(2, _omitFieldNames ? '' : 'password')
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  CreateAccountRequest clone() => CreateAccountRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  CreateAccountRequest copyWith(void Function(CreateAccountRequest) updates) => super.copyWith((message) => updates(message as CreateAccountRequest)) as CreateAccountRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static CreateAccountRequest create() => CreateAccountRequest._();
+  CreateAccountRequest createEmptyInstance() => create();
+  static $pb.PbList<CreateAccountRequest> createRepeated() => $pb.PbList<CreateAccountRequest>();
+  @$core.pragma('dart2js:noInline')
+  static CreateAccountRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<CreateAccountRequest>(create);
+  static CreateAccountRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get email => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set email($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasEmail() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearEmail() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.String get password => $_getSZ(1);
+  @$pb.TagNumber(2)
+  set password($core.String v) { $_setString(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasPassword() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearPassword() => clearField(2);
+}
+
+class CreateAccountResponse extends $pb.GeneratedMessage {
+  factory CreateAccountResponse({
+    $2.Account? account,
+  }) {
+    final $result = create();
+    if (account != null) {
+      $result.account = account;
+    }
+    return $result;
+  }
+  CreateAccountResponse._() : super();
+  factory CreateAccountResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory CreateAccountResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CreateAccountResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOM<$2.Account>(1, _omitFieldNames ? '' : 'account', subBuilder: $2.Account.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  CreateAccountResponse clone() => CreateAccountResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  CreateAccountResponse copyWith(void Function(CreateAccountResponse) updates) => super.copyWith((message) => updates(message as CreateAccountResponse)) as CreateAccountResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static CreateAccountResponse create() => CreateAccountResponse._();
+  CreateAccountResponse createEmptyInstance() => create();
+  static $pb.PbList<CreateAccountResponse> createRepeated() => $pb.PbList<CreateAccountResponse>();
+  @$core.pragma('dart2js:noInline')
+  static CreateAccountResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<CreateAccountResponse>(create);
+  static CreateAccountResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $2.Account get account => $_getN(0);
+  @$pb.TagNumber(1)
+  set account($2.Account v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccount() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccount() => clearField(1);
+  @$pb.TagNumber(1)
+  $2.Account ensureAccount() => $_ensure(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_create_account.pbenum.dart b/frontend/app/lib/pb/rpc_create_account.pbenum.dart
new file mode 100644
index 0000000..6e09c97
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_create_account.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_create_account.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_create_account.pbjson.dart b/frontend/app/lib/pb/rpc_create_account.pbjson.dart
new file mode 100644
index 0000000..3a99698
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_create_account.pbjson.dart
@@ -0,0 +1,47 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_create_account.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use createAccountRequestDescriptor instead')
+const CreateAccountRequest$json = {
+  '1': 'CreateAccountRequest',
+  '2': [
+    {'1': 'email', '3': 1, '4': 1, '5': 9, '10': 'email'},
+    {'1': 'password', '3': 2, '4': 1, '5': 9, '10': 'password'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `CreateAccountRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List createAccountRequestDescriptor = $convert.base64Decode(
+    'ChRDcmVhdGVBY2NvdW50UmVxdWVzdBIUCgVlbWFpbBgBIAEoCVIFZW1haWwSGgoIcGFzc3dvcm'
+    'QYAiABKAlSCHBhc3N3b3JkOoQBkkGAAQo2Kg5DcmVhdGUgQWNjb3VudDIRQ3JlYXRlIGFuIEFj'
+    'Y291bnTSAQVlbWFpbNIBCHBhc3N3b3JkMkZ7ImVtYWlsIjogImpvaG4uZG9lQGV4YW1wbGUuY2'
+    '9tIiwgInBhc3N3b3JkIjogIk1heVRoZUZvcmNlQmVXaXRoWW91ISJ9');
+
+@$core.Deprecated('Use createAccountResponseDescriptor instead')
+const CreateAccountResponse$json = {
+  '1': 'CreateAccountResponse',
+  '2': [
+    {'1': 'account', '3': 1, '4': 1, '5': 11, '6': '.pb.Account', '8': {}, '10': 'account'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `CreateAccountResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List createAccountResponseDescriptor = $convert.base64Decode(
+    'ChVDcmVhdGVBY2NvdW50UmVzcG9uc2USKgoHYWNjb3VudBgBIAEoCzILLnBiLkFjY291bnRCA5'
+    'JBAFIHYWNjb3VudDozkkEwCi4qD0NyZWF0ZWQgQWNjb3VudDIbUmV0dXJucyB0aGUgY3JlYXRl'
+    'ZCBBY2NvdW50');
+
diff --git a/frontend/app/lib/pb/rpc_create_account.pbserver.dart b/frontend/app/lib/pb/rpc_create_account.pbserver.dart
new file mode 100644
index 0000000..533f0eb
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_create_account.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_create_account.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_create_account.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_create_account_info.pb.dart b/frontend/app/lib/pb/rpc_create_account_info.pb.dart
new file mode 100644
index 0000000..2ae91f1
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_create_account_info.pb.dart
@@ -0,0 +1,252 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_create_account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'account_info.pb.dart' as $1;
+import 'google/protobuf/timestamp.pb.dart' as $0;
+
+class CreateAccountInfoRequest extends $pb.GeneratedMessage {
+  factory CreateAccountInfoRequest({
+    $fixnum.Int64? accountId,
+    $core.String? firstname,
+    $core.String? lastname,
+    $core.String? street,
+    $core.String? city,
+    $core.String? zip,
+    $core.String? country,
+    $core.String? phone,
+    $0.Timestamp? birthday,
+    $core.bool? privacyAccepted,
+  }) {
+    final $result = create();
+    if (accountId != null) {
+      $result.accountId = accountId;
+    }
+    if (firstname != null) {
+      $result.firstname = firstname;
+    }
+    if (lastname != null) {
+      $result.lastname = lastname;
+    }
+    if (street != null) {
+      $result.street = street;
+    }
+    if (city != null) {
+      $result.city = city;
+    }
+    if (zip != null) {
+      $result.zip = zip;
+    }
+    if (country != null) {
+      $result.country = country;
+    }
+    if (phone != null) {
+      $result.phone = phone;
+    }
+    if (birthday != null) {
+      $result.birthday = birthday;
+    }
+    if (privacyAccepted != null) {
+      $result.privacyAccepted = privacyAccepted;
+    }
+    return $result;
+  }
+  CreateAccountInfoRequest._() : super();
+  factory CreateAccountInfoRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory CreateAccountInfoRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CreateAccountInfoRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'accountId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..aOS(3, _omitFieldNames ? '' : 'firstname')
+    ..aOS(4, _omitFieldNames ? '' : 'lastname')
+    ..aOS(5, _omitFieldNames ? '' : 'street')
+    ..aOS(6, _omitFieldNames ? '' : 'city')
+    ..aOS(7, _omitFieldNames ? '' : 'zip')
+    ..aOS(8, _omitFieldNames ? '' : 'country')
+    ..aOS(9, _omitFieldNames ? '' : 'phone')
+    ..aOM<$0.Timestamp>(10, _omitFieldNames ? '' : 'birthday', subBuilder: $0.Timestamp.create)
+    ..aOB(11, _omitFieldNames ? '' : 'privacyAccepted')
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  CreateAccountInfoRequest clone() => CreateAccountInfoRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  CreateAccountInfoRequest copyWith(void Function(CreateAccountInfoRequest) updates) => super.copyWith((message) => updates(message as CreateAccountInfoRequest)) as CreateAccountInfoRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static CreateAccountInfoRequest create() => CreateAccountInfoRequest._();
+  CreateAccountInfoRequest createEmptyInstance() => create();
+  static $pb.PbList<CreateAccountInfoRequest> createRepeated() => $pb.PbList<CreateAccountInfoRequest>();
+  @$core.pragma('dart2js:noInline')
+  static CreateAccountInfoRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<CreateAccountInfoRequest>(create);
+  static CreateAccountInfoRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get accountId => $_getI64(0);
+  @$pb.TagNumber(1)
+  set accountId($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccountId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccountId() => clearField(1);
+
+  @$pb.TagNumber(3)
+  $core.String get firstname => $_getSZ(1);
+  @$pb.TagNumber(3)
+  set firstname($core.String v) { $_setString(1, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasFirstname() => $_has(1);
+  @$pb.TagNumber(3)
+  void clearFirstname() => clearField(3);
+
+  @$pb.TagNumber(4)
+  $core.String get lastname => $_getSZ(2);
+  @$pb.TagNumber(4)
+  set lastname($core.String v) { $_setString(2, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasLastname() => $_has(2);
+  @$pb.TagNumber(4)
+  void clearLastname() => clearField(4);
+
+  @$pb.TagNumber(5)
+  $core.String get street => $_getSZ(3);
+  @$pb.TagNumber(5)
+  set street($core.String v) { $_setString(3, v); }
+  @$pb.TagNumber(5)
+  $core.bool hasStreet() => $_has(3);
+  @$pb.TagNumber(5)
+  void clearStreet() => clearField(5);
+
+  @$pb.TagNumber(6)
+  $core.String get city => $_getSZ(4);
+  @$pb.TagNumber(6)
+  set city($core.String v) { $_setString(4, v); }
+  @$pb.TagNumber(6)
+  $core.bool hasCity() => $_has(4);
+  @$pb.TagNumber(6)
+  void clearCity() => clearField(6);
+
+  @$pb.TagNumber(7)
+  $core.String get zip => $_getSZ(5);
+  @$pb.TagNumber(7)
+  set zip($core.String v) { $_setString(5, v); }
+  @$pb.TagNumber(7)
+  $core.bool hasZip() => $_has(5);
+  @$pb.TagNumber(7)
+  void clearZip() => clearField(7);
+
+  @$pb.TagNumber(8)
+  $core.String get country => $_getSZ(6);
+  @$pb.TagNumber(8)
+  set country($core.String v) { $_setString(6, v); }
+  @$pb.TagNumber(8)
+  $core.bool hasCountry() => $_has(6);
+  @$pb.TagNumber(8)
+  void clearCountry() => clearField(8);
+
+  @$pb.TagNumber(9)
+  $core.String get phone => $_getSZ(7);
+  @$pb.TagNumber(9)
+  set phone($core.String v) { $_setString(7, v); }
+  @$pb.TagNumber(9)
+  $core.bool hasPhone() => $_has(7);
+  @$pb.TagNumber(9)
+  void clearPhone() => clearField(9);
+
+  @$pb.TagNumber(10)
+  $0.Timestamp get birthday => $_getN(8);
+  @$pb.TagNumber(10)
+  set birthday($0.Timestamp v) { setField(10, v); }
+  @$pb.TagNumber(10)
+  $core.bool hasBirthday() => $_has(8);
+  @$pb.TagNumber(10)
+  void clearBirthday() => clearField(10);
+  @$pb.TagNumber(10)
+  $0.Timestamp ensureBirthday() => $_ensure(8);
+
+  @$pb.TagNumber(11)
+  $core.bool get privacyAccepted => $_getBF(9);
+  @$pb.TagNumber(11)
+  set privacyAccepted($core.bool v) { $_setBool(9, v); }
+  @$pb.TagNumber(11)
+  $core.bool hasPrivacyAccepted() => $_has(9);
+  @$pb.TagNumber(11)
+  void clearPrivacyAccepted() => clearField(11);
+}
+
+class CreateAccountInfoResponse extends $pb.GeneratedMessage {
+  factory CreateAccountInfoResponse({
+    $1.AccountInfo? accountInfo,
+  }) {
+    final $result = create();
+    if (accountInfo != null) {
+      $result.accountInfo = accountInfo;
+    }
+    return $result;
+  }
+  CreateAccountInfoResponse._() : super();
+  factory CreateAccountInfoResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory CreateAccountInfoResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CreateAccountInfoResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOM<$1.AccountInfo>(1, _omitFieldNames ? '' : 'accountInfo', subBuilder: $1.AccountInfo.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  CreateAccountInfoResponse clone() => CreateAccountInfoResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  CreateAccountInfoResponse copyWith(void Function(CreateAccountInfoResponse) updates) => super.copyWith((message) => updates(message as CreateAccountInfoResponse)) as CreateAccountInfoResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static CreateAccountInfoResponse create() => CreateAccountInfoResponse._();
+  CreateAccountInfoResponse createEmptyInstance() => create();
+  static $pb.PbList<CreateAccountInfoResponse> createRepeated() => $pb.PbList<CreateAccountInfoResponse>();
+  @$core.pragma('dart2js:noInline')
+  static CreateAccountInfoResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<CreateAccountInfoResponse>(create);
+  static CreateAccountInfoResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $1.AccountInfo get accountInfo => $_getN(0);
+  @$pb.TagNumber(1)
+  set accountInfo($1.AccountInfo v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccountInfo() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccountInfo() => clearField(1);
+  @$pb.TagNumber(1)
+  $1.AccountInfo ensureAccountInfo() => $_ensure(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_create_account_info.pbenum.dart b/frontend/app/lib/pb/rpc_create_account_info.pbenum.dart
new file mode 100644
index 0000000..f60d4eb
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_create_account_info.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_create_account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_create_account_info.pbjson.dart b/frontend/app/lib/pb/rpc_create_account_info.pbjson.dart
new file mode 100644
index 0000000..f5ff3e6
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_create_account_info.pbjson.dart
@@ -0,0 +1,67 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_create_account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use createAccountInfoRequestDescriptor instead')
+const CreateAccountInfoRequest$json = {
+  '1': 'CreateAccountInfoRequest',
+  '2': [
+    {'1': 'account_id', '3': 1, '4': 1, '5': 4, '10': 'accountId'},
+    {'1': 'firstname', '3': 3, '4': 1, '5': 9, '10': 'firstname'},
+    {'1': 'lastname', '3': 4, '4': 1, '5': 9, '10': 'lastname'},
+    {'1': 'street', '3': 5, '4': 1, '5': 9, '10': 'street'},
+    {'1': 'city', '3': 6, '4': 1, '5': 9, '10': 'city'},
+    {'1': 'zip', '3': 7, '4': 1, '5': 9, '10': 'zip'},
+    {'1': 'country', '3': 8, '4': 1, '5': 9, '10': 'country'},
+    {'1': 'phone', '3': 9, '4': 1, '5': 9, '10': 'phone'},
+    {'1': 'birthday', '3': 10, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'birthday'},
+    {'1': 'privacy_accepted', '3': 11, '4': 1, '5': 8, '8': {}, '9': 0, '10': 'privacyAccepted', '17': true},
+  ],
+  '7': {},
+  '8': [
+    {'1': '_privacy_accepted'},
+  ],
+};
+
+/// Descriptor for `CreateAccountInfoRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List createAccountInfoRequestDescriptor = $convert.base64Decode(
+    'ChhDcmVhdGVBY2NvdW50SW5mb1JlcXVlc3QSHQoKYWNjb3VudF9pZBgBIAEoBFIJYWNjb3VudE'
+    'lkEhwKCWZpcnN0bmFtZRgDIAEoCVIJZmlyc3RuYW1lEhoKCGxhc3RuYW1lGAQgASgJUghsYXN0'
+    'bmFtZRIWCgZzdHJlZXQYBSABKAlSBnN0cmVldBISCgRjaXR5GAYgASgJUgRjaXR5EhAKA3ppcB'
+    'gHIAEoCVIDemlwEhgKB2NvdW50cnkYCCABKAlSB2NvdW50cnkSFAoFcGhvbmUYCSABKAlSBXBo'
+    'b25lElMKCGJpcnRoZGF5GAogASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcEIbkkEYSh'
+    'YiMTk5MC0xMC0wNVQwMDowMDowMFoiUghiaXJ0aGRheRI5ChBwcml2YWN5X2FjY2VwdGVkGAsg'
+    'ASgIQgmSQQZKBHRydWVIAFIPcHJpdmFjeUFjY2VwdGVkiAEBOrICkkGuAgp6KhJDcmVhdGUgQW'
+    'Njb3VudEluZm8yFUNyZWF0ZSBhbiBBY2NvdW50SW5mb9IBCmFjY291bnRfaWTSAQlmaXJzdG5h'
+    'bWXSAQhsYXN0bmFtZdIBBnN0cmVldNIBBGNpdHnSAQN6aXDSAQdjb3VudHJ50gEIYmlydGhkYX'
+    'kyrwF7ImFjY291bnRfaWQiOiAiMSIsICJmaXJzdG5hbWUiOiAiSm9obiIsICJsYXN0bmFtZSI6'
+    'ICJEb2UiLCAic3RyZWV0IjogIk1haW4gU3RyZWV0IDEiLCAiemlwIjogIjA4MTUiLCAiY2l0eS'
+    'I6ICJOZXcgWW9yayIsICJjb3VudHJ5IjogIlVTQSIsICJiaXJ0aGRheSI6ICIxOTkwLTEwLTA1'
+    'VDAwOjAwOjAwWiJ9QhMKEV9wcml2YWN5X2FjY2VwdGVk');
+
+@$core.Deprecated('Use createAccountInfoResponseDescriptor instead')
+const CreateAccountInfoResponse$json = {
+  '1': 'CreateAccountInfoResponse',
+  '2': [
+    {'1': 'account_info', '3': 1, '4': 1, '5': 11, '6': '.pb.AccountInfo', '8': {}, '10': 'accountInfo'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `CreateAccountInfoResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List createAccountInfoResponseDescriptor = $convert.base64Decode(
+    'ChlDcmVhdGVBY2NvdW50SW5mb1Jlc3BvbnNlEjcKDGFjY291bnRfaW5mbxgBIAEoCzIPLnBiLk'
+    'FjY291bnRJbmZvQgOSQQBSC2FjY291bnRJbmZvOjuSQTgKNioTQ3JlYXRlZCBBY2NvdW50SW5m'
+    'bzIfUmV0dXJucyB0aGUgY3JlYXRlZCBBY2NvdW50SW5mbw==');
+
diff --git a/frontend/app/lib/pb/rpc_create_account_info.pbserver.dart b/frontend/app/lib/pb/rpc_create_account_info.pbserver.dart
new file mode 100644
index 0000000..36d73df
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_create_account_info.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_create_account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_create_account_info.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_create_payment.pb.dart b/frontend/app/lib/pb/rpc_create_payment.pb.dart
new file mode 100644
index 0000000..bed6474
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_create_payment.pb.dart
@@ -0,0 +1,235 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_create_payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'payment.pb.dart' as $3;
+
+class CreatePaymentRequest extends $pb.GeneratedMessage {
+  factory CreatePaymentRequest({
+    $fixnum.Int64? accountId,
+    $core.String? paymentCategory,
+    $core.String? bankname,
+    $core.String? iBAN,
+    $core.String? bIC,
+    $core.String? paypalAccount,
+    $core.String? paypalId,
+    $core.String? paymentSystem,
+    $core.String? type,
+  }) {
+    final $result = create();
+    if (accountId != null) {
+      $result.accountId = accountId;
+    }
+    if (paymentCategory != null) {
+      $result.paymentCategory = paymentCategory;
+    }
+    if (bankname != null) {
+      $result.bankname = bankname;
+    }
+    if (iBAN != null) {
+      $result.iBAN = iBAN;
+    }
+    if (bIC != null) {
+      $result.bIC = bIC;
+    }
+    if (paypalAccount != null) {
+      $result.paypalAccount = paypalAccount;
+    }
+    if (paypalId != null) {
+      $result.paypalId = paypalId;
+    }
+    if (paymentSystem != null) {
+      $result.paymentSystem = paymentSystem;
+    }
+    if (type != null) {
+      $result.type = type;
+    }
+    return $result;
+  }
+  CreatePaymentRequest._() : super();
+  factory CreatePaymentRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory CreatePaymentRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CreatePaymentRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'accountId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..aOS(2, _omitFieldNames ? '' : 'paymentCategory')
+    ..aOS(3, _omitFieldNames ? '' : 'bankname')
+    ..aOS(4, _omitFieldNames ? '' : 'IBAN', protoName: 'IBAN')
+    ..aOS(5, _omitFieldNames ? '' : 'BIC', protoName: 'BIC')
+    ..aOS(6, _omitFieldNames ? '' : 'paypalAccount')
+    ..aOS(7, _omitFieldNames ? '' : 'paypalId')
+    ..aOS(8, _omitFieldNames ? '' : 'paymentSystem')
+    ..aOS(9, _omitFieldNames ? '' : 'type')
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  CreatePaymentRequest clone() => CreatePaymentRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  CreatePaymentRequest copyWith(void Function(CreatePaymentRequest) updates) => super.copyWith((message) => updates(message as CreatePaymentRequest)) as CreatePaymentRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static CreatePaymentRequest create() => CreatePaymentRequest._();
+  CreatePaymentRequest createEmptyInstance() => create();
+  static $pb.PbList<CreatePaymentRequest> createRepeated() => $pb.PbList<CreatePaymentRequest>();
+  @$core.pragma('dart2js:noInline')
+  static CreatePaymentRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<CreatePaymentRequest>(create);
+  static CreatePaymentRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get accountId => $_getI64(0);
+  @$pb.TagNumber(1)
+  set accountId($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccountId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccountId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.String get paymentCategory => $_getSZ(1);
+  @$pb.TagNumber(2)
+  set paymentCategory($core.String v) { $_setString(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasPaymentCategory() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearPaymentCategory() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $core.String get bankname => $_getSZ(2);
+  @$pb.TagNumber(3)
+  set bankname($core.String v) { $_setString(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasBankname() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearBankname() => clearField(3);
+
+  @$pb.TagNumber(4)
+  $core.String get iBAN => $_getSZ(3);
+  @$pb.TagNumber(4)
+  set iBAN($core.String v) { $_setString(3, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasIBAN() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearIBAN() => clearField(4);
+
+  @$pb.TagNumber(5)
+  $core.String get bIC => $_getSZ(4);
+  @$pb.TagNumber(5)
+  set bIC($core.String v) { $_setString(4, v); }
+  @$pb.TagNumber(5)
+  $core.bool hasBIC() => $_has(4);
+  @$pb.TagNumber(5)
+  void clearBIC() => clearField(5);
+
+  @$pb.TagNumber(6)
+  $core.String get paypalAccount => $_getSZ(5);
+  @$pb.TagNumber(6)
+  set paypalAccount($core.String v) { $_setString(5, v); }
+  @$pb.TagNumber(6)
+  $core.bool hasPaypalAccount() => $_has(5);
+  @$pb.TagNumber(6)
+  void clearPaypalAccount() => clearField(6);
+
+  @$pb.TagNumber(7)
+  $core.String get paypalId => $_getSZ(6);
+  @$pb.TagNumber(7)
+  set paypalId($core.String v) { $_setString(6, v); }
+  @$pb.TagNumber(7)
+  $core.bool hasPaypalId() => $_has(6);
+  @$pb.TagNumber(7)
+  void clearPaypalId() => clearField(7);
+
+  @$pb.TagNumber(8)
+  $core.String get paymentSystem => $_getSZ(7);
+  @$pb.TagNumber(8)
+  set paymentSystem($core.String v) { $_setString(7, v); }
+  @$pb.TagNumber(8)
+  $core.bool hasPaymentSystem() => $_has(7);
+  @$pb.TagNumber(8)
+  void clearPaymentSystem() => clearField(8);
+
+  @$pb.TagNumber(9)
+  $core.String get type => $_getSZ(8);
+  @$pb.TagNumber(9)
+  set type($core.String v) { $_setString(8, v); }
+  @$pb.TagNumber(9)
+  $core.bool hasType() => $_has(8);
+  @$pb.TagNumber(9)
+  void clearType() => clearField(9);
+}
+
+class CreatePaymentResponse extends $pb.GeneratedMessage {
+  factory CreatePaymentResponse({
+    $3.Payment? payment,
+  }) {
+    final $result = create();
+    if (payment != null) {
+      $result.payment = payment;
+    }
+    return $result;
+  }
+  CreatePaymentResponse._() : super();
+  factory CreatePaymentResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory CreatePaymentResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CreatePaymentResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOM<$3.Payment>(1, _omitFieldNames ? '' : 'payment', subBuilder: $3.Payment.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  CreatePaymentResponse clone() => CreatePaymentResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  CreatePaymentResponse copyWith(void Function(CreatePaymentResponse) updates) => super.copyWith((message) => updates(message as CreatePaymentResponse)) as CreatePaymentResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static CreatePaymentResponse create() => CreatePaymentResponse._();
+  CreatePaymentResponse createEmptyInstance() => create();
+  static $pb.PbList<CreatePaymentResponse> createRepeated() => $pb.PbList<CreatePaymentResponse>();
+  @$core.pragma('dart2js:noInline')
+  static CreatePaymentResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<CreatePaymentResponse>(create);
+  static CreatePaymentResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $3.Payment get payment => $_getN(0);
+  @$pb.TagNumber(1)
+  set payment($3.Payment v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasPayment() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearPayment() => clearField(1);
+  @$pb.TagNumber(1)
+  $3.Payment ensurePayment() => $_ensure(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_create_payment.pbenum.dart b/frontend/app/lib/pb/rpc_create_payment.pbenum.dart
new file mode 100644
index 0000000..30d4bb1
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_create_payment.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_create_payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_create_payment.pbjson.dart b/frontend/app/lib/pb/rpc_create_payment.pbjson.dart
new file mode 100644
index 0000000..ffe63b1
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_create_payment.pbjson.dart
@@ -0,0 +1,71 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_create_payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use createPaymentRequestDescriptor instead')
+const CreatePaymentRequest$json = {
+  '1': 'CreatePaymentRequest',
+  '2': [
+    {'1': 'account_id', '3': 1, '4': 1, '5': 4, '10': 'accountId'},
+    {'1': 'payment_category', '3': 2, '4': 1, '5': 9, '10': 'paymentCategory'},
+    {'1': 'bankname', '3': 3, '4': 1, '5': 9, '9': 0, '10': 'bankname', '17': true},
+    {'1': 'IBAN', '3': 4, '4': 1, '5': 9, '9': 1, '10': 'IBAN', '17': true},
+    {'1': 'BIC', '3': 5, '4': 1, '5': 9, '9': 2, '10': 'BIC', '17': true},
+    {'1': 'paypal_account', '3': 6, '4': 1, '5': 9, '9': 3, '10': 'paypalAccount', '17': true},
+    {'1': 'paypal_id', '3': 7, '4': 1, '5': 9, '9': 4, '10': 'paypalId', '17': true},
+    {'1': 'payment_system', '3': 8, '4': 1, '5': 9, '9': 5, '10': 'paymentSystem', '17': true},
+    {'1': 'type', '3': 9, '4': 1, '5': 9, '10': 'type'},
+  ],
+  '7': {},
+  '8': [
+    {'1': '_bankname'},
+    {'1': '_IBAN'},
+    {'1': '_BIC'},
+    {'1': '_paypal_account'},
+    {'1': '_paypal_id'},
+    {'1': '_payment_system'},
+  ],
+};
+
+/// Descriptor for `CreatePaymentRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List createPaymentRequestDescriptor = $convert.base64Decode(
+    'ChRDcmVhdGVQYXltZW50UmVxdWVzdBIdCgphY2NvdW50X2lkGAEgASgEUglhY2NvdW50SWQSKQ'
+    'oQcGF5bWVudF9jYXRlZ29yeRgCIAEoCVIPcGF5bWVudENhdGVnb3J5Eh8KCGJhbmtuYW1lGAMg'
+    'ASgJSABSCGJhbmtuYW1liAEBEhcKBElCQU4YBCABKAlIAVIESUJBTogBARIVCgNCSUMYBSABKA'
+    'lIAlIDQklDiAEBEioKDnBheXBhbF9hY2NvdW50GAYgASgJSANSDXBheXBhbEFjY291bnSIAQES'
+    'IAoJcGF5cGFsX2lkGAcgASgJSARSCHBheXBhbElkiAEBEioKDnBheW1lbnRfc3lzdGVtGAggAS'
+    'gJSAVSDXBheW1lbnRTeXN0ZW2IAQESEgoEdHlwZRgJIAEoCVIEdHlwZTqZApJBlQIKSioOQ3Jl'
+    'YXRlIFBheW1lbnQyEUNyZWF0ZSBhbiBQYXltZW500gEKYWNjb3VudF9pZNIBEHBheW1lbnRfY2'
+    'F0ZWdvcnnSAQR0eXBlMsYBeyJhY2NvdW50X2lkIjogIjEiLCAicGF5bWVudF9jYXRlZ29yeSI6'
+    'ICJUQkQ6IHBheXBhbCIsICJwYXlwYWxfYWNjb3VudCI6ICJqb2huLmRvZUBleGFtcGxlLmNvbS'
+    'IsICJwYXlwYWxfaWQiOiAidGhpcy1pcy1hLXBheXBhbC1pZCIsICJwYXltZW50X3N5c3RlbSI6'
+    'ICJUQkQ6IHBheXBhbCBzeXN0ZW0iLCAidHlwZSI6ICJUQkQ6IHNvbWUgdHlwZSJ9QgsKCV9iYW'
+    '5rbmFtZUIHCgVfSUJBTkIGCgRfQklDQhEKD19wYXlwYWxfYWNjb3VudEIMCgpfcGF5cGFsX2lk'
+    'QhEKD19wYXltZW50X3N5c3RlbQ==');
+
+@$core.Deprecated('Use createPaymentResponseDescriptor instead')
+const CreatePaymentResponse$json = {
+  '1': 'CreatePaymentResponse',
+  '2': [
+    {'1': 'payment', '3': 1, '4': 1, '5': 11, '6': '.pb.Payment', '8': {}, '10': 'payment'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `CreatePaymentResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List createPaymentResponseDescriptor = $convert.base64Decode(
+    'ChVDcmVhdGVQYXltZW50UmVzcG9uc2USKgoHcGF5bWVudBgBIAEoCzILLnBiLlBheW1lbnRCA5'
+    'JBAFIHcGF5bWVudDozkkEwCi4qD0NyZWF0ZWQgUGF5bWVudDIbUmV0dXJucyB0aGUgY3JlYXRl'
+    'ZCBQYXltZW50');
+
diff --git a/frontend/app/lib/pb/rpc_create_payment.pbserver.dart b/frontend/app/lib/pb/rpc_create_payment.pbserver.dart
new file mode 100644
index 0000000..c732f6e
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_create_payment.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_create_payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_create_payment.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_create_person.pb.dart b/frontend/app/lib/pb/rpc_create_person.pb.dart
new file mode 100644
index 0000000..35dcb1a
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_create_person.pb.dart
@@ -0,0 +1,224 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_create_person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'google/protobuf/timestamp.pb.dart' as $0;
+import 'person.pb.dart' as $4;
+
+class CreatePersonRequest extends $pb.GeneratedMessage {
+  factory CreatePersonRequest({
+    $fixnum.Int64? accountId,
+    $core.String? firstname,
+    $core.String? lastname,
+    $core.String? street,
+    $core.String? city,
+    $core.String? zip,
+    $core.String? country,
+    $0.Timestamp? birthday,
+  }) {
+    final $result = create();
+    if (accountId != null) {
+      $result.accountId = accountId;
+    }
+    if (firstname != null) {
+      $result.firstname = firstname;
+    }
+    if (lastname != null) {
+      $result.lastname = lastname;
+    }
+    if (street != null) {
+      $result.street = street;
+    }
+    if (city != null) {
+      $result.city = city;
+    }
+    if (zip != null) {
+      $result.zip = zip;
+    }
+    if (country != null) {
+      $result.country = country;
+    }
+    if (birthday != null) {
+      $result.birthday = birthday;
+    }
+    return $result;
+  }
+  CreatePersonRequest._() : super();
+  factory CreatePersonRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory CreatePersonRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CreatePersonRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'accountId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..aOS(2, _omitFieldNames ? '' : 'firstname')
+    ..aOS(3, _omitFieldNames ? '' : 'lastname')
+    ..aOS(4, _omitFieldNames ? '' : 'street')
+    ..aOS(5, _omitFieldNames ? '' : 'city')
+    ..aOS(6, _omitFieldNames ? '' : 'zip')
+    ..aOS(7, _omitFieldNames ? '' : 'country')
+    ..aOM<$0.Timestamp>(8, _omitFieldNames ? '' : 'birthday', subBuilder: $0.Timestamp.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  CreatePersonRequest clone() => CreatePersonRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  CreatePersonRequest copyWith(void Function(CreatePersonRequest) updates) => super.copyWith((message) => updates(message as CreatePersonRequest)) as CreatePersonRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static CreatePersonRequest create() => CreatePersonRequest._();
+  CreatePersonRequest createEmptyInstance() => create();
+  static $pb.PbList<CreatePersonRequest> createRepeated() => $pb.PbList<CreatePersonRequest>();
+  @$core.pragma('dart2js:noInline')
+  static CreatePersonRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<CreatePersonRequest>(create);
+  static CreatePersonRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get accountId => $_getI64(0);
+  @$pb.TagNumber(1)
+  set accountId($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccountId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccountId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.String get firstname => $_getSZ(1);
+  @$pb.TagNumber(2)
+  set firstname($core.String v) { $_setString(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasFirstname() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearFirstname() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $core.String get lastname => $_getSZ(2);
+  @$pb.TagNumber(3)
+  set lastname($core.String v) { $_setString(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasLastname() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearLastname() => clearField(3);
+
+  @$pb.TagNumber(4)
+  $core.String get street => $_getSZ(3);
+  @$pb.TagNumber(4)
+  set street($core.String v) { $_setString(3, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasStreet() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearStreet() => clearField(4);
+
+  @$pb.TagNumber(5)
+  $core.String get city => $_getSZ(4);
+  @$pb.TagNumber(5)
+  set city($core.String v) { $_setString(4, v); }
+  @$pb.TagNumber(5)
+  $core.bool hasCity() => $_has(4);
+  @$pb.TagNumber(5)
+  void clearCity() => clearField(5);
+
+  @$pb.TagNumber(6)
+  $core.String get zip => $_getSZ(5);
+  @$pb.TagNumber(6)
+  set zip($core.String v) { $_setString(5, v); }
+  @$pb.TagNumber(6)
+  $core.bool hasZip() => $_has(5);
+  @$pb.TagNumber(6)
+  void clearZip() => clearField(6);
+
+  @$pb.TagNumber(7)
+  $core.String get country => $_getSZ(6);
+  @$pb.TagNumber(7)
+  set country($core.String v) { $_setString(6, v); }
+  @$pb.TagNumber(7)
+  $core.bool hasCountry() => $_has(6);
+  @$pb.TagNumber(7)
+  void clearCountry() => clearField(7);
+
+  @$pb.TagNumber(8)
+  $0.Timestamp get birthday => $_getN(7);
+  @$pb.TagNumber(8)
+  set birthday($0.Timestamp v) { setField(8, v); }
+  @$pb.TagNumber(8)
+  $core.bool hasBirthday() => $_has(7);
+  @$pb.TagNumber(8)
+  void clearBirthday() => clearField(8);
+  @$pb.TagNumber(8)
+  $0.Timestamp ensureBirthday() => $_ensure(7);
+}
+
+class CreatePersonResponse extends $pb.GeneratedMessage {
+  factory CreatePersonResponse({
+    $4.Person? person,
+  }) {
+    final $result = create();
+    if (person != null) {
+      $result.person = person;
+    }
+    return $result;
+  }
+  CreatePersonResponse._() : super();
+  factory CreatePersonResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory CreatePersonResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CreatePersonResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOM<$4.Person>(1, _omitFieldNames ? '' : 'person', subBuilder: $4.Person.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  CreatePersonResponse clone() => CreatePersonResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  CreatePersonResponse copyWith(void Function(CreatePersonResponse) updates) => super.copyWith((message) => updates(message as CreatePersonResponse)) as CreatePersonResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static CreatePersonResponse create() => CreatePersonResponse._();
+  CreatePersonResponse createEmptyInstance() => create();
+  static $pb.PbList<CreatePersonResponse> createRepeated() => $pb.PbList<CreatePersonResponse>();
+  @$core.pragma('dart2js:noInline')
+  static CreatePersonResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<CreatePersonResponse>(create);
+  static CreatePersonResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $4.Person get person => $_getN(0);
+  @$pb.TagNumber(1)
+  set person($4.Person v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasPerson() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearPerson() => clearField(1);
+  @$pb.TagNumber(1)
+  $4.Person ensurePerson() => $_ensure(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_create_person.pbenum.dart b/frontend/app/lib/pb/rpc_create_person.pbenum.dart
new file mode 100644
index 0000000..3af5c20
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_create_person.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_create_person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_create_person.pbjson.dart b/frontend/app/lib/pb/rpc_create_person.pbjson.dart
new file mode 100644
index 0000000..5f7b61b
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_create_person.pbjson.dart
@@ -0,0 +1,60 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_create_person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use createPersonRequestDescriptor instead')
+const CreatePersonRequest$json = {
+  '1': 'CreatePersonRequest',
+  '2': [
+    {'1': 'account_id', '3': 1, '4': 1, '5': 4, '10': 'accountId'},
+    {'1': 'firstname', '3': 2, '4': 1, '5': 9, '10': 'firstname'},
+    {'1': 'lastname', '3': 3, '4': 1, '5': 9, '10': 'lastname'},
+    {'1': 'street', '3': 4, '4': 1, '5': 9, '10': 'street'},
+    {'1': 'city', '3': 5, '4': 1, '5': 9, '10': 'city'},
+    {'1': 'zip', '3': 6, '4': 1, '5': 9, '10': 'zip'},
+    {'1': 'country', '3': 7, '4': 1, '5': 9, '10': 'country'},
+    {'1': 'birthday', '3': 8, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'birthday'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `CreatePersonRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List createPersonRequestDescriptor = $convert.base64Decode(
+    'ChNDcmVhdGVQZXJzb25SZXF1ZXN0Eh0KCmFjY291bnRfaWQYASABKARSCWFjY291bnRJZBIcCg'
+    'lmaXJzdG5hbWUYAiABKAlSCWZpcnN0bmFtZRIaCghsYXN0bmFtZRgDIAEoCVIIbGFzdG5hbWUS'
+    'FgoGc3RyZWV0GAQgASgJUgZzdHJlZXQSEgoEY2l0eRgFIAEoCVIEY2l0eRIQCgN6aXAYBiABKA'
+    'lSA3ppcBIYCgdjb3VudHJ5GAcgASgJUgdjb3VudHJ5ElMKCGJpcnRoZGF5GAggASgLMhouZ29v'
+    'Z2xlLnByb3RvYnVmLlRpbWVzdGFtcEIbkkEYShYiMTk5MC0xMC0wNVQwMDowMDowMFoiUghiaX'
+    'J0aGRheTqpApJBpQIKcCoNQ3JlYXRlIFBlcnNvbjIQQ3JlYXRlIGFuIFBlcnNvbtIBCmFjY291'
+    'bnRfaWTSAQlmaXJzdG5hbWXSAQhsYXN0bmFtZdIBBnN0cmVldNIBBGNpdHnSAQN6aXDSAQdjb3'
+    'VudHJ50gEIYmlydGhkYXkysAF7ICJhY2NvdW50X2lkIjogIjEiLCAiZmlyc3RuYW1lIjogIkpv'
+    'aG4iLCAibGFzdG5hbWUiOiAiRG9lIiwgInN0cmVldCI6ICJNYWluIFN0cmVldCAxIiwgInppcC'
+    'I6ICIwODE1IiwgImNpdHkiOiAiTmV3IFlvcmsiLCAiY291bnRyeSI6ICJVU0EiLCAiYmlydGhk'
+    'YXkiOiAiMTk5MC0xMC0wNVQwMDowMDowMFoifQ==');
+
+@$core.Deprecated('Use createPersonResponseDescriptor instead')
+const CreatePersonResponse$json = {
+  '1': 'CreatePersonResponse',
+  '2': [
+    {'1': 'person', '3': 1, '4': 1, '5': 11, '6': '.pb.Person', '8': {}, '10': 'person'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `CreatePersonResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List createPersonResponseDescriptor = $convert.base64Decode(
+    'ChRDcmVhdGVQZXJzb25SZXNwb25zZRInCgZwZXJzb24YASABKAsyCi5wYi5QZXJzb25CA5JBAF'
+    'IGcGVyc29uOjGSQS4KLCoOQ3JlYXRlZCBQZXJzb24yGlJldHVybnMgdGhlIGNyZWF0ZWQgUGVy'
+    'c29u');
+
diff --git a/frontend/app/lib/pb/rpc_create_person.pbserver.dart b/frontend/app/lib/pb/rpc_create_person.pbserver.dart
new file mode 100644
index 0000000..2b5f8fd
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_create_person.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_create_person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_create_person.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_delete_document.pb.dart b/frontend/app/lib/pb/rpc_delete_document.pb.dart
new file mode 100644
index 0000000..b471494
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_delete_document.pb.dart
@@ -0,0 +1,133 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_delete_document.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+class DeleteDocumentRequest extends $pb.GeneratedMessage {
+  factory DeleteDocumentRequest({
+    $fixnum.Int64? id,
+  }) {
+    final $result = create();
+    if (id != null) {
+      $result.id = id;
+    }
+    return $result;
+  }
+  DeleteDocumentRequest._() : super();
+  factory DeleteDocumentRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory DeleteDocumentRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'DeleteDocumentRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  DeleteDocumentRequest clone() => DeleteDocumentRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  DeleteDocumentRequest copyWith(void Function(DeleteDocumentRequest) updates) => super.copyWith((message) => updates(message as DeleteDocumentRequest)) as DeleteDocumentRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static DeleteDocumentRequest create() => DeleteDocumentRequest._();
+  DeleteDocumentRequest createEmptyInstance() => create();
+  static $pb.PbList<DeleteDocumentRequest> createRepeated() => $pb.PbList<DeleteDocumentRequest>();
+  @$core.pragma('dart2js:noInline')
+  static DeleteDocumentRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<DeleteDocumentRequest>(create);
+  static DeleteDocumentRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get id => $_getI64(0);
+  @$pb.TagNumber(1)
+  set id($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearId() => clearField(1);
+}
+
+class DeleteDocumentResponse extends $pb.GeneratedMessage {
+  factory DeleteDocumentResponse({
+    $fixnum.Int64? id,
+    $core.bool? deleted,
+  }) {
+    final $result = create();
+    if (id != null) {
+      $result.id = id;
+    }
+    if (deleted != null) {
+      $result.deleted = deleted;
+    }
+    return $result;
+  }
+  DeleteDocumentResponse._() : super();
+  factory DeleteDocumentResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory DeleteDocumentResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'DeleteDocumentResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..aOB(2, _omitFieldNames ? '' : 'deleted')
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  DeleteDocumentResponse clone() => DeleteDocumentResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  DeleteDocumentResponse copyWith(void Function(DeleteDocumentResponse) updates) => super.copyWith((message) => updates(message as DeleteDocumentResponse)) as DeleteDocumentResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static DeleteDocumentResponse create() => DeleteDocumentResponse._();
+  DeleteDocumentResponse createEmptyInstance() => create();
+  static $pb.PbList<DeleteDocumentResponse> createRepeated() => $pb.PbList<DeleteDocumentResponse>();
+  @$core.pragma('dart2js:noInline')
+  static DeleteDocumentResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<DeleteDocumentResponse>(create);
+  static DeleteDocumentResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get id => $_getI64(0);
+  @$pb.TagNumber(1)
+  set id($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.bool get deleted => $_getBF(1);
+  @$pb.TagNumber(2)
+  set deleted($core.bool v) { $_setBool(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasDeleted() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearDeleted() => clearField(2);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_delete_document.pbenum.dart b/frontend/app/lib/pb/rpc_delete_document.pbenum.dart
new file mode 100644
index 0000000..56c8377
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_delete_document.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_delete_document.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_delete_document.pbjson.dart b/frontend/app/lib/pb/rpc_delete_document.pbjson.dart
new file mode 100644
index 0000000..35c319c
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_delete_document.pbjson.dart
@@ -0,0 +1,45 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_delete_document.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use deleteDocumentRequestDescriptor instead')
+const DeleteDocumentRequest$json = {
+  '1': 'DeleteDocumentRequest',
+  '2': [
+    {'1': 'id', '3': 1, '4': 1, '5': 4, '10': 'id'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `DeleteDocumentRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List deleteDocumentRequestDescriptor = $convert.base64Decode(
+    'ChVEZWxldGVEb2N1bWVudFJlcXVlc3QSDgoCaWQYASABKARSAmlkOjuSQTgKKSoPRGVsZXRlIE'
+    'RvY3VtZW50MhFEZWxldGUgYSBEb2N1bWVudNIBAmlkMgt7ImlkIjogIjEifQ==');
+
+@$core.Deprecated('Use deleteDocumentResponseDescriptor instead')
+const DeleteDocumentResponse$json = {
+  '1': 'DeleteDocumentResponse',
+  '2': [
+    {'1': 'id', '3': 1, '4': 1, '5': 4, '10': 'id'},
+    {'1': 'deleted', '3': 2, '4': 1, '5': 8, '10': 'deleted'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `DeleteDocumentResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List deleteDocumentResponseDescriptor = $convert.base64Decode(
+    'ChZEZWxldGVEb2N1bWVudFJlc3BvbnNlEg4KAmlkGAEgASgEUgJpZBIYCgdkZWxldGVkGAIgAS'
+    'gIUgdkZWxldGVkOj2SQToKGioYRGVsZXRlIERvY3VtZW50IFJlc3BvbnNlMhx7ImlkIjogIjEi'
+    'LCAiZGVsZXRlZCI6IHRydWV9');
+
diff --git a/frontend/app/lib/pb/rpc_delete_document.pbserver.dart b/frontend/app/lib/pb/rpc_delete_document.pbserver.dart
new file mode 100644
index 0000000..57d37b6
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_delete_document.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_delete_document.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_delete_document.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_delete_payment.pb.dart b/frontend/app/lib/pb/rpc_delete_payment.pb.dart
new file mode 100644
index 0000000..62cdcac
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_delete_payment.pb.dart
@@ -0,0 +1,133 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_delete_payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+class DeletePaymentRequest extends $pb.GeneratedMessage {
+  factory DeletePaymentRequest({
+    $fixnum.Int64? id,
+  }) {
+    final $result = create();
+    if (id != null) {
+      $result.id = id;
+    }
+    return $result;
+  }
+  DeletePaymentRequest._() : super();
+  factory DeletePaymentRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory DeletePaymentRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'DeletePaymentRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  DeletePaymentRequest clone() => DeletePaymentRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  DeletePaymentRequest copyWith(void Function(DeletePaymentRequest) updates) => super.copyWith((message) => updates(message as DeletePaymentRequest)) as DeletePaymentRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static DeletePaymentRequest create() => DeletePaymentRequest._();
+  DeletePaymentRequest createEmptyInstance() => create();
+  static $pb.PbList<DeletePaymentRequest> createRepeated() => $pb.PbList<DeletePaymentRequest>();
+  @$core.pragma('dart2js:noInline')
+  static DeletePaymentRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<DeletePaymentRequest>(create);
+  static DeletePaymentRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get id => $_getI64(0);
+  @$pb.TagNumber(1)
+  set id($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearId() => clearField(1);
+}
+
+class DeletePaymentResponse extends $pb.GeneratedMessage {
+  factory DeletePaymentResponse({
+    $fixnum.Int64? id,
+    $core.bool? deleted,
+  }) {
+    final $result = create();
+    if (id != null) {
+      $result.id = id;
+    }
+    if (deleted != null) {
+      $result.deleted = deleted;
+    }
+    return $result;
+  }
+  DeletePaymentResponse._() : super();
+  factory DeletePaymentResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory DeletePaymentResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'DeletePaymentResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..aOB(2, _omitFieldNames ? '' : 'deleted')
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  DeletePaymentResponse clone() => DeletePaymentResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  DeletePaymentResponse copyWith(void Function(DeletePaymentResponse) updates) => super.copyWith((message) => updates(message as DeletePaymentResponse)) as DeletePaymentResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static DeletePaymentResponse create() => DeletePaymentResponse._();
+  DeletePaymentResponse createEmptyInstance() => create();
+  static $pb.PbList<DeletePaymentResponse> createRepeated() => $pb.PbList<DeletePaymentResponse>();
+  @$core.pragma('dart2js:noInline')
+  static DeletePaymentResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<DeletePaymentResponse>(create);
+  static DeletePaymentResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get id => $_getI64(0);
+  @$pb.TagNumber(1)
+  set id($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.bool get deleted => $_getBF(1);
+  @$pb.TagNumber(2)
+  set deleted($core.bool v) { $_setBool(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasDeleted() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearDeleted() => clearField(2);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_delete_payment.pbenum.dart b/frontend/app/lib/pb/rpc_delete_payment.pbenum.dart
new file mode 100644
index 0000000..13f3a74
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_delete_payment.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_delete_payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_delete_payment.pbjson.dart b/frontend/app/lib/pb/rpc_delete_payment.pbjson.dart
new file mode 100644
index 0000000..5571a0f
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_delete_payment.pbjson.dart
@@ -0,0 +1,45 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_delete_payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use deletePaymentRequestDescriptor instead')
+const DeletePaymentRequest$json = {
+  '1': 'DeletePaymentRequest',
+  '2': [
+    {'1': 'id', '3': 1, '4': 1, '5': 4, '10': 'id'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `DeletePaymentRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List deletePaymentRequestDescriptor = $convert.base64Decode(
+    'ChREZWxldGVQYXltZW50UmVxdWVzdBIOCgJpZBgBIAEoBFICaWQ6OZJBNgonKg5EZWxldGUgUG'
+    'F5bWVudDIQRGVsZXRlIGEgUGF5bWVudNIBAmlkMgt7ImlkIjogIjEifQ==');
+
+@$core.Deprecated('Use deletePaymentResponseDescriptor instead')
+const DeletePaymentResponse$json = {
+  '1': 'DeletePaymentResponse',
+  '2': [
+    {'1': 'id', '3': 1, '4': 1, '5': 4, '10': 'id'},
+    {'1': 'deleted', '3': 2, '4': 1, '5': 8, '10': 'deleted'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `DeletePaymentResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List deletePaymentResponseDescriptor = $convert.base64Decode(
+    'ChVEZWxldGVQYXltZW50UmVzcG9uc2USDgoCaWQYASABKARSAmlkEhgKB2RlbGV0ZWQYAiABKA'
+    'hSB2RlbGV0ZWQ6PJJBOQoZKhdEZWxldGUgUGF5bWVudCBSZXNwb25zZTIceyJpZCI6ICIxIiwg'
+    'ImRlbGV0ZWQiOiB0cnVlfQ==');
+
diff --git a/frontend/app/lib/pb/rpc_delete_payment.pbserver.dart b/frontend/app/lib/pb/rpc_delete_payment.pbserver.dart
new file mode 100644
index 0000000..4e22b6f
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_delete_payment.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_delete_payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_delete_payment.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_delete_person.pb.dart b/frontend/app/lib/pb/rpc_delete_person.pb.dart
new file mode 100644
index 0000000..693d2a0
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_delete_person.pb.dart
@@ -0,0 +1,133 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_delete_person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+class DeletePersonRequest extends $pb.GeneratedMessage {
+  factory DeletePersonRequest({
+    $fixnum.Int64? id,
+  }) {
+    final $result = create();
+    if (id != null) {
+      $result.id = id;
+    }
+    return $result;
+  }
+  DeletePersonRequest._() : super();
+  factory DeletePersonRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory DeletePersonRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'DeletePersonRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  DeletePersonRequest clone() => DeletePersonRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  DeletePersonRequest copyWith(void Function(DeletePersonRequest) updates) => super.copyWith((message) => updates(message as DeletePersonRequest)) as DeletePersonRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static DeletePersonRequest create() => DeletePersonRequest._();
+  DeletePersonRequest createEmptyInstance() => create();
+  static $pb.PbList<DeletePersonRequest> createRepeated() => $pb.PbList<DeletePersonRequest>();
+  @$core.pragma('dart2js:noInline')
+  static DeletePersonRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<DeletePersonRequest>(create);
+  static DeletePersonRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get id => $_getI64(0);
+  @$pb.TagNumber(1)
+  set id($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearId() => clearField(1);
+}
+
+class DeletePersonResponse extends $pb.GeneratedMessage {
+  factory DeletePersonResponse({
+    $fixnum.Int64? id,
+    $core.bool? deleted,
+  }) {
+    final $result = create();
+    if (id != null) {
+      $result.id = id;
+    }
+    if (deleted != null) {
+      $result.deleted = deleted;
+    }
+    return $result;
+  }
+  DeletePersonResponse._() : super();
+  factory DeletePersonResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory DeletePersonResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'DeletePersonResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..aOB(2, _omitFieldNames ? '' : 'deleted')
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  DeletePersonResponse clone() => DeletePersonResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  DeletePersonResponse copyWith(void Function(DeletePersonResponse) updates) => super.copyWith((message) => updates(message as DeletePersonResponse)) as DeletePersonResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static DeletePersonResponse create() => DeletePersonResponse._();
+  DeletePersonResponse createEmptyInstance() => create();
+  static $pb.PbList<DeletePersonResponse> createRepeated() => $pb.PbList<DeletePersonResponse>();
+  @$core.pragma('dart2js:noInline')
+  static DeletePersonResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<DeletePersonResponse>(create);
+  static DeletePersonResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get id => $_getI64(0);
+  @$pb.TagNumber(1)
+  set id($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.bool get deleted => $_getBF(1);
+  @$pb.TagNumber(2)
+  set deleted($core.bool v) { $_setBool(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasDeleted() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearDeleted() => clearField(2);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_delete_person.pbenum.dart b/frontend/app/lib/pb/rpc_delete_person.pbenum.dart
new file mode 100644
index 0000000..9425fb1
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_delete_person.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_delete_person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_delete_person.pbjson.dart b/frontend/app/lib/pb/rpc_delete_person.pbjson.dart
new file mode 100644
index 0000000..d77eafe
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_delete_person.pbjson.dart
@@ -0,0 +1,45 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_delete_person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use deletePersonRequestDescriptor instead')
+const DeletePersonRequest$json = {
+  '1': 'DeletePersonRequest',
+  '2': [
+    {'1': 'id', '3': 1, '4': 1, '5': 4, '10': 'id'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `DeletePersonRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List deletePersonRequestDescriptor = $convert.base64Decode(
+    'ChNEZWxldGVQZXJzb25SZXF1ZXN0Eg4KAmlkGAEgASgEUgJpZDo3kkE0CiUqDURlbGV0ZSBQZX'
+    'Jzb24yD0RlbGV0ZSBhIFBlcnNvbtIBAmlkMgt7ImlkIjogIjEifQ==');
+
+@$core.Deprecated('Use deletePersonResponseDescriptor instead')
+const DeletePersonResponse$json = {
+  '1': 'DeletePersonResponse',
+  '2': [
+    {'1': 'id', '3': 1, '4': 1, '5': 4, '10': 'id'},
+    {'1': 'deleted', '3': 2, '4': 1, '5': 8, '10': 'deleted'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `DeletePersonResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List deletePersonResponseDescriptor = $convert.base64Decode(
+    'ChREZWxldGVQZXJzb25SZXNwb25zZRIOCgJpZBgBIAEoBFICaWQSGAoHZGVsZXRlZBgCIAEoCF'
+    'IHZGVsZXRlZDo7kkE4ChgqFkRlbGV0ZSBQZXJzb24gUmVzcG9uc2UyHHsiaWQiOiAiMSIsICJk'
+    'ZWxldGVkIjogdHJ1ZX0=');
+
diff --git a/frontend/app/lib/pb/rpc_delete_person.pbserver.dart b/frontend/app/lib/pb/rpc_delete_person.pbserver.dart
new file mode 100644
index 0000000..1fd5c66
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_delete_person.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_delete_person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_delete_person.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_get_account.pb.dart b/frontend/app/lib/pb/rpc_get_account.pb.dart
new file mode 100644
index 0000000..8d129d1
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_get_account.pb.dart
@@ -0,0 +1,123 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_get_account.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'account.pb.dart' as $2;
+
+class GetAccountRequest extends $pb.GeneratedMessage {
+  factory GetAccountRequest({
+    $fixnum.Int64? id,
+  }) {
+    final $result = create();
+    if (id != null) {
+      $result.id = id;
+    }
+    return $result;
+  }
+  GetAccountRequest._() : super();
+  factory GetAccountRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetAccountRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetAccountRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetAccountRequest clone() => GetAccountRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetAccountRequest copyWith(void Function(GetAccountRequest) updates) => super.copyWith((message) => updates(message as GetAccountRequest)) as GetAccountRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetAccountRequest create() => GetAccountRequest._();
+  GetAccountRequest createEmptyInstance() => create();
+  static $pb.PbList<GetAccountRequest> createRepeated() => $pb.PbList<GetAccountRequest>();
+  @$core.pragma('dart2js:noInline')
+  static GetAccountRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetAccountRequest>(create);
+  static GetAccountRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get id => $_getI64(0);
+  @$pb.TagNumber(1)
+  set id($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearId() => clearField(1);
+}
+
+class GetAccountResponse extends $pb.GeneratedMessage {
+  factory GetAccountResponse({
+    $2.Account? account,
+  }) {
+    final $result = create();
+    if (account != null) {
+      $result.account = account;
+    }
+    return $result;
+  }
+  GetAccountResponse._() : super();
+  factory GetAccountResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetAccountResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetAccountResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOM<$2.Account>(1, _omitFieldNames ? '' : 'account', subBuilder: $2.Account.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetAccountResponse clone() => GetAccountResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetAccountResponse copyWith(void Function(GetAccountResponse) updates) => super.copyWith((message) => updates(message as GetAccountResponse)) as GetAccountResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetAccountResponse create() => GetAccountResponse._();
+  GetAccountResponse createEmptyInstance() => create();
+  static $pb.PbList<GetAccountResponse> createRepeated() => $pb.PbList<GetAccountResponse>();
+  @$core.pragma('dart2js:noInline')
+  static GetAccountResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetAccountResponse>(create);
+  static GetAccountResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $2.Account get account => $_getN(0);
+  @$pb.TagNumber(1)
+  set account($2.Account v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccount() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccount() => clearField(1);
+  @$pb.TagNumber(1)
+  $2.Account ensureAccount() => $_ensure(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_get_account.pbenum.dart b/frontend/app/lib/pb/rpc_get_account.pbenum.dart
new file mode 100644
index 0000000..0292510
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_get_account.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_get_account.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_get_account.pbjson.dart b/frontend/app/lib/pb/rpc_get_account.pbjson.dart
new file mode 100644
index 0000000..bf5309a
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_get_account.pbjson.dart
@@ -0,0 +1,44 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_get_account.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use getAccountRequestDescriptor instead')
+const GetAccountRequest$json = {
+  '1': 'GetAccountRequest',
+  '2': [
+    {'1': 'id', '3': 1, '4': 1, '5': 4, '10': 'id'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `GetAccountRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getAccountRequestDescriptor = $convert.base64Decode(
+    'ChFHZXRBY2NvdW50UmVxdWVzdBIOCgJpZBgBIAEoBFICaWQ6Q5JBQAowKgpHZXRBY2NvdW50Mh'
+    '1HZXQgQWNjb3VudEluZm8gYnkgYWNjb3VudF9pZNIBAmlkMgx7ImlkIjogIjEiIH0=');
+
+@$core.Deprecated('Use getAccountResponseDescriptor instead')
+const GetAccountResponse$json = {
+  '1': 'GetAccountResponse',
+  '2': [
+    {'1': 'account', '3': 1, '4': 1, '5': 11, '6': '.pb.Account', '8': {}, '10': 'account'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `GetAccountResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getAccountResponseDescriptor = $convert.base64Decode(
+    'ChJHZXRBY2NvdW50UmVzcG9uc2USKgoHYWNjb3VudBgBIAEoCzILLnBiLkFjY291bnRCA5JBAF'
+    'IHYWNjb3VudDozkkEwCi4qE0dldEFjY291bnQgUmVzcG9uc2UyF1JldHVybnMgdGhlIEFjY291'
+    'bnRJbmZv');
+
diff --git a/frontend/app/lib/pb/rpc_get_account.pbserver.dart b/frontend/app/lib/pb/rpc_get_account.pbserver.dart
new file mode 100644
index 0000000..d2c87f6
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_get_account.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_get_account.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_get_account.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_get_account_info.pb.dart b/frontend/app/lib/pb/rpc_get_account_info.pb.dart
new file mode 100644
index 0000000..d11787f
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_get_account_info.pb.dart
@@ -0,0 +1,123 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_get_account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'account_info.pb.dart' as $1;
+
+class GetAccountInfoRequest extends $pb.GeneratedMessage {
+  factory GetAccountInfoRequest({
+    $fixnum.Int64? accountId,
+  }) {
+    final $result = create();
+    if (accountId != null) {
+      $result.accountId = accountId;
+    }
+    return $result;
+  }
+  GetAccountInfoRequest._() : super();
+  factory GetAccountInfoRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetAccountInfoRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetAccountInfoRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'accountId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetAccountInfoRequest clone() => GetAccountInfoRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetAccountInfoRequest copyWith(void Function(GetAccountInfoRequest) updates) => super.copyWith((message) => updates(message as GetAccountInfoRequest)) as GetAccountInfoRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetAccountInfoRequest create() => GetAccountInfoRequest._();
+  GetAccountInfoRequest createEmptyInstance() => create();
+  static $pb.PbList<GetAccountInfoRequest> createRepeated() => $pb.PbList<GetAccountInfoRequest>();
+  @$core.pragma('dart2js:noInline')
+  static GetAccountInfoRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetAccountInfoRequest>(create);
+  static GetAccountInfoRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get accountId => $_getI64(0);
+  @$pb.TagNumber(1)
+  set accountId($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccountId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccountId() => clearField(1);
+}
+
+class GetAccountInfoResponse extends $pb.GeneratedMessage {
+  factory GetAccountInfoResponse({
+    $1.AccountInfo? accountInfo,
+  }) {
+    final $result = create();
+    if (accountInfo != null) {
+      $result.accountInfo = accountInfo;
+    }
+    return $result;
+  }
+  GetAccountInfoResponse._() : super();
+  factory GetAccountInfoResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetAccountInfoResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetAccountInfoResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOM<$1.AccountInfo>(1, _omitFieldNames ? '' : 'accountInfo', subBuilder: $1.AccountInfo.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetAccountInfoResponse clone() => GetAccountInfoResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetAccountInfoResponse copyWith(void Function(GetAccountInfoResponse) updates) => super.copyWith((message) => updates(message as GetAccountInfoResponse)) as GetAccountInfoResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetAccountInfoResponse create() => GetAccountInfoResponse._();
+  GetAccountInfoResponse createEmptyInstance() => create();
+  static $pb.PbList<GetAccountInfoResponse> createRepeated() => $pb.PbList<GetAccountInfoResponse>();
+  @$core.pragma('dart2js:noInline')
+  static GetAccountInfoResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetAccountInfoResponse>(create);
+  static GetAccountInfoResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $1.AccountInfo get accountInfo => $_getN(0);
+  @$pb.TagNumber(1)
+  set accountInfo($1.AccountInfo v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccountInfo() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccountInfo() => clearField(1);
+  @$pb.TagNumber(1)
+  $1.AccountInfo ensureAccountInfo() => $_ensure(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_get_account_info.pbenum.dart b/frontend/app/lib/pb/rpc_get_account_info.pbenum.dart
new file mode 100644
index 0000000..2a2b0b3
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_get_account_info.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_get_account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_get_account_info.pbjson.dart b/frontend/app/lib/pb/rpc_get_account_info.pbjson.dart
new file mode 100644
index 0000000..1d19aec
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_get_account_info.pbjson.dart
@@ -0,0 +1,45 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_get_account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use getAccountInfoRequestDescriptor instead')
+const GetAccountInfoRequest$json = {
+  '1': 'GetAccountInfoRequest',
+  '2': [
+    {'1': 'account_id', '3': 1, '4': 1, '5': 4, '10': 'accountId'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `GetAccountInfoRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getAccountInfoRequestDescriptor = $convert.base64Decode(
+    'ChVHZXRBY2NvdW50SW5mb1JlcXVlc3QSHQoKYWNjb3VudF9pZBgBIAEoBFIJYWNjb3VudElkOl'
+    'eSQVQKPCoOR2V0QWNjb3VudEluZm8yHUdldCBBY2NvdW50SW5mbyBieSBhY2NvdW50X2lk0gEK'
+    'YWNjb3VudF9pZDIUeyJhY2NvdW50X2lkIjogIjEiIH0=');
+
+@$core.Deprecated('Use getAccountInfoResponseDescriptor instead')
+const GetAccountInfoResponse$json = {
+  '1': 'GetAccountInfoResponse',
+  '2': [
+    {'1': 'account_info', '3': 1, '4': 1, '5': 11, '6': '.pb.AccountInfo', '8': {}, '10': 'accountInfo'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `GetAccountInfoResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getAccountInfoResponseDescriptor = $convert.base64Decode(
+    'ChZHZXRBY2NvdW50SW5mb1Jlc3BvbnNlEjcKDGFjY291bnRfaW5mbxgBIAEoCzIPLnBiLkFjY2'
+    '91bnRJbmZvQgOSQQBSC2FjY291bnRJbmZvOjeSQTQKMioXR2V0QWNjb3VudEluZm8gUmVzcG9u'
+    'c2UyF1JldHVybnMgdGhlIEFjY291bnRJbmZv');
+
diff --git a/frontend/app/lib/pb/rpc_get_account_info.pbserver.dart b/frontend/app/lib/pb/rpc_get_account_info.pbserver.dart
new file mode 100644
index 0000000..82075ad
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_get_account_info.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_get_account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_get_account_info.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_get_payment.pb.dart b/frontend/app/lib/pb/rpc_get_payment.pb.dart
new file mode 100644
index 0000000..526b590
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_get_payment.pb.dart
@@ -0,0 +1,123 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_get_payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'payment.pb.dart' as $3;
+
+class GetPaymentRequest extends $pb.GeneratedMessage {
+  factory GetPaymentRequest({
+    $fixnum.Int64? id,
+  }) {
+    final $result = create();
+    if (id != null) {
+      $result.id = id;
+    }
+    return $result;
+  }
+  GetPaymentRequest._() : super();
+  factory GetPaymentRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetPaymentRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetPaymentRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetPaymentRequest clone() => GetPaymentRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetPaymentRequest copyWith(void Function(GetPaymentRequest) updates) => super.copyWith((message) => updates(message as GetPaymentRequest)) as GetPaymentRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetPaymentRequest create() => GetPaymentRequest._();
+  GetPaymentRequest createEmptyInstance() => create();
+  static $pb.PbList<GetPaymentRequest> createRepeated() => $pb.PbList<GetPaymentRequest>();
+  @$core.pragma('dart2js:noInline')
+  static GetPaymentRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetPaymentRequest>(create);
+  static GetPaymentRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get id => $_getI64(0);
+  @$pb.TagNumber(1)
+  set id($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearId() => clearField(1);
+}
+
+class GetPaymentResponse extends $pb.GeneratedMessage {
+  factory GetPaymentResponse({
+    $3.Payment? payment,
+  }) {
+    final $result = create();
+    if (payment != null) {
+      $result.payment = payment;
+    }
+    return $result;
+  }
+  GetPaymentResponse._() : super();
+  factory GetPaymentResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetPaymentResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetPaymentResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOM<$3.Payment>(1, _omitFieldNames ? '' : 'payment', subBuilder: $3.Payment.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetPaymentResponse clone() => GetPaymentResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetPaymentResponse copyWith(void Function(GetPaymentResponse) updates) => super.copyWith((message) => updates(message as GetPaymentResponse)) as GetPaymentResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetPaymentResponse create() => GetPaymentResponse._();
+  GetPaymentResponse createEmptyInstance() => create();
+  static $pb.PbList<GetPaymentResponse> createRepeated() => $pb.PbList<GetPaymentResponse>();
+  @$core.pragma('dart2js:noInline')
+  static GetPaymentResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetPaymentResponse>(create);
+  static GetPaymentResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $3.Payment get payment => $_getN(0);
+  @$pb.TagNumber(1)
+  set payment($3.Payment v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasPayment() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearPayment() => clearField(1);
+  @$pb.TagNumber(1)
+  $3.Payment ensurePayment() => $_ensure(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_get_payment.pbenum.dart b/frontend/app/lib/pb/rpc_get_payment.pbenum.dart
new file mode 100644
index 0000000..cfd3cde
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_get_payment.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_get_payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_get_payment.pbjson.dart b/frontend/app/lib/pb/rpc_get_payment.pbjson.dart
new file mode 100644
index 0000000..d43eb5d
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_get_payment.pbjson.dart
@@ -0,0 +1,44 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_get_payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use getPaymentRequestDescriptor instead')
+const GetPaymentRequest$json = {
+  '1': 'GetPaymentRequest',
+  '2': [
+    {'1': 'id', '3': 1, '4': 1, '5': 4, '10': 'id'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `GetPaymentRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getPaymentRequestDescriptor = $convert.base64Decode(
+    'ChFHZXRQYXltZW50UmVxdWVzdBIOCgJpZBgBIAEoBFICaWQ6OpJBNwonKgpHZXRQYXltZW50Mh'
+    'RHZXQgYW4gUGF5bWVudCBieSBJRNIBAmlkMgx7ImlkIjogIjEiIH0=');
+
+@$core.Deprecated('Use getPaymentResponseDescriptor instead')
+const GetPaymentResponse$json = {
+  '1': 'GetPaymentResponse',
+  '2': [
+    {'1': 'payment', '3': 1, '4': 1, '5': 11, '6': '.pb.Payment', '8': {}, '10': 'payment'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `GetPaymentResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getPaymentResponseDescriptor = $convert.base64Decode(
+    'ChJHZXRQYXltZW50UmVzcG9uc2USKgoHcGF5bWVudBgBIAEoCzILLnBiLlBheW1lbnRCA5JBAF'
+    'IHcGF5bWVudDovkkEsCioqE0dldFBheW1lbnQgUmVzcG9uc2UyE1JldHVybnMgdGhlIFBheW1l'
+    'bnQ=');
+
diff --git a/frontend/app/lib/pb/rpc_get_payment.pbserver.dart b/frontend/app/lib/pb/rpc_get_payment.pbserver.dart
new file mode 100644
index 0000000..b758155
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_get_payment.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_get_payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_get_payment.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_get_person.pb.dart b/frontend/app/lib/pb/rpc_get_person.pb.dart
new file mode 100644
index 0000000..5b5badf
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_get_person.pb.dart
@@ -0,0 +1,123 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_get_person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'person.pb.dart' as $4;
+
+class GetPersonRequest extends $pb.GeneratedMessage {
+  factory GetPersonRequest({
+    $fixnum.Int64? id,
+  }) {
+    final $result = create();
+    if (id != null) {
+      $result.id = id;
+    }
+    return $result;
+  }
+  GetPersonRequest._() : super();
+  factory GetPersonRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetPersonRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetPersonRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetPersonRequest clone() => GetPersonRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetPersonRequest copyWith(void Function(GetPersonRequest) updates) => super.copyWith((message) => updates(message as GetPersonRequest)) as GetPersonRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetPersonRequest create() => GetPersonRequest._();
+  GetPersonRequest createEmptyInstance() => create();
+  static $pb.PbList<GetPersonRequest> createRepeated() => $pb.PbList<GetPersonRequest>();
+  @$core.pragma('dart2js:noInline')
+  static GetPersonRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetPersonRequest>(create);
+  static GetPersonRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get id => $_getI64(0);
+  @$pb.TagNumber(1)
+  set id($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearId() => clearField(1);
+}
+
+class GetPersonResponse extends $pb.GeneratedMessage {
+  factory GetPersonResponse({
+    $4.Person? person,
+  }) {
+    final $result = create();
+    if (person != null) {
+      $result.person = person;
+    }
+    return $result;
+  }
+  GetPersonResponse._() : super();
+  factory GetPersonResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory GetPersonResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetPersonResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOM<$4.Person>(1, _omitFieldNames ? '' : 'person', subBuilder: $4.Person.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  GetPersonResponse clone() => GetPersonResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  GetPersonResponse copyWith(void Function(GetPersonResponse) updates) => super.copyWith((message) => updates(message as GetPersonResponse)) as GetPersonResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static GetPersonResponse create() => GetPersonResponse._();
+  GetPersonResponse createEmptyInstance() => create();
+  static $pb.PbList<GetPersonResponse> createRepeated() => $pb.PbList<GetPersonResponse>();
+  @$core.pragma('dart2js:noInline')
+  static GetPersonResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<GetPersonResponse>(create);
+  static GetPersonResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $4.Person get person => $_getN(0);
+  @$pb.TagNumber(1)
+  set person($4.Person v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasPerson() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearPerson() => clearField(1);
+  @$pb.TagNumber(1)
+  $4.Person ensurePerson() => $_ensure(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_get_person.pbenum.dart b/frontend/app/lib/pb/rpc_get_person.pbenum.dart
new file mode 100644
index 0000000..5912e89
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_get_person.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_get_person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_get_person.pbjson.dart b/frontend/app/lib/pb/rpc_get_person.pbjson.dart
new file mode 100644
index 0000000..25ecf45
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_get_person.pbjson.dart
@@ -0,0 +1,43 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_get_person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use getPersonRequestDescriptor instead')
+const GetPersonRequest$json = {
+  '1': 'GetPersonRequest',
+  '2': [
+    {'1': 'id', '3': 1, '4': 1, '5': 4, '10': 'id'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `GetPersonRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getPersonRequestDescriptor = $convert.base64Decode(
+    'ChBHZXRQZXJzb25SZXF1ZXN0Eg4KAmlkGAEgASgEUgJpZDo4kkE1CiUqCUdldFBlcnNvbjITR2'
+    'V0IGFuIFBlcnNvbiBieSBJRNIBAmlkMgx7ImlkIjogIjEiIH0=');
+
+@$core.Deprecated('Use getPersonResponseDescriptor instead')
+const GetPersonResponse$json = {
+  '1': 'GetPersonResponse',
+  '2': [
+    {'1': 'person', '3': 1, '4': 1, '5': 11, '6': '.pb.Person', '8': {}, '10': 'person'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `GetPersonResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List getPersonResponseDescriptor = $convert.base64Decode(
+    'ChFHZXRQZXJzb25SZXNwb25zZRInCgZwZXJzb24YASABKAsyCi5wYi5QZXJzb25CA5JBAFIGcG'
+    'Vyc29uOi2SQSoKKCoSR2V0UGVyc29uIFJlc3BvbnNlMhJSZXR1cm5zIHRoZSBQZXJzb24=');
+
diff --git a/frontend/app/lib/pb/rpc_get_person.pbserver.dart b/frontend/app/lib/pb/rpc_get_person.pbserver.dart
new file mode 100644
index 0000000..d182110
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_get_person.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_get_person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_get_person.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_list_account_info.pb.dart b/frontend/app/lib/pb/rpc_list_account_info.pb.dart
new file mode 100644
index 0000000..9e12410
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_account_info.pb.dart
@@ -0,0 +1,128 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'account_info.pb.dart' as $1;
+
+class ListAccountInfoRequest extends $pb.GeneratedMessage {
+  factory ListAccountInfoRequest({
+    $core.int? pageId,
+    $core.int? pageSize,
+  }) {
+    final $result = create();
+    if (pageId != null) {
+      $result.pageId = pageId;
+    }
+    if (pageSize != null) {
+      $result.pageSize = pageSize;
+    }
+    return $result;
+  }
+  ListAccountInfoRequest._() : super();
+  factory ListAccountInfoRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ListAccountInfoRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListAccountInfoRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$core.int>(1, _omitFieldNames ? '' : 'pageId', $pb.PbFieldType.OU3)
+    ..a<$core.int>(2, _omitFieldNames ? '' : 'pageSize', $pb.PbFieldType.OU3)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  ListAccountInfoRequest clone() => ListAccountInfoRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ListAccountInfoRequest copyWith(void Function(ListAccountInfoRequest) updates) => super.copyWith((message) => updates(message as ListAccountInfoRequest)) as ListAccountInfoRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static ListAccountInfoRequest create() => ListAccountInfoRequest._();
+  ListAccountInfoRequest createEmptyInstance() => create();
+  static $pb.PbList<ListAccountInfoRequest> createRepeated() => $pb.PbList<ListAccountInfoRequest>();
+  @$core.pragma('dart2js:noInline')
+  static ListAccountInfoRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ListAccountInfoRequest>(create);
+  static ListAccountInfoRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.int get pageId => $_getIZ(0);
+  @$pb.TagNumber(1)
+  set pageId($core.int v) { $_setUnsignedInt32(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasPageId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearPageId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.int get pageSize => $_getIZ(1);
+  @$pb.TagNumber(2)
+  set pageSize($core.int v) { $_setUnsignedInt32(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasPageSize() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearPageSize() => clearField(2);
+}
+
+class ListAccountInfoResponse extends $pb.GeneratedMessage {
+  factory ListAccountInfoResponse({
+    $core.Iterable<$1.AccountInfo>? accountInfo,
+  }) {
+    final $result = create();
+    if (accountInfo != null) {
+      $result.accountInfo.addAll(accountInfo);
+    }
+    return $result;
+  }
+  ListAccountInfoResponse._() : super();
+  factory ListAccountInfoResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ListAccountInfoResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListAccountInfoResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..pc<$1.AccountInfo>(1, _omitFieldNames ? '' : 'accountInfo', $pb.PbFieldType.PM, subBuilder: $1.AccountInfo.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  ListAccountInfoResponse clone() => ListAccountInfoResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ListAccountInfoResponse copyWith(void Function(ListAccountInfoResponse) updates) => super.copyWith((message) => updates(message as ListAccountInfoResponse)) as ListAccountInfoResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static ListAccountInfoResponse create() => ListAccountInfoResponse._();
+  ListAccountInfoResponse createEmptyInstance() => create();
+  static $pb.PbList<ListAccountInfoResponse> createRepeated() => $pb.PbList<ListAccountInfoResponse>();
+  @$core.pragma('dart2js:noInline')
+  static ListAccountInfoResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ListAccountInfoResponse>(create);
+  static ListAccountInfoResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.List<$1.AccountInfo> get accountInfo => $_getList(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_list_account_info.pbenum.dart b/frontend/app/lib/pb/rpc_list_account_info.pbenum.dart
new file mode 100644
index 0000000..25f91fb
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_account_info.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_list_account_info.pbjson.dart b/frontend/app/lib/pb/rpc_list_account_info.pbjson.dart
new file mode 100644
index 0000000..6d5c4d3
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_account_info.pbjson.dart
@@ -0,0 +1,47 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use listAccountInfoRequestDescriptor instead')
+const ListAccountInfoRequest$json = {
+  '1': 'ListAccountInfoRequest',
+  '2': [
+    {'1': 'page_id', '3': 1, '4': 1, '5': 13, '10': 'pageId'},
+    {'1': 'page_size', '3': 2, '4': 1, '5': 13, '10': 'pageSize'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `ListAccountInfoRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List listAccountInfoRequestDescriptor = $convert.base64Decode(
+    'ChZMaXN0QWNjb3VudEluZm9SZXF1ZXN0EhcKB3BhZ2VfaWQYASABKA1SBnBhZ2VJZBIbCglwYW'
+    'dlX3NpemUYAiABKA1SCHBhZ2VTaXplOmqSQWcKQyoPTGlzdEFjY291bnRJbmZvMhpSZXR1cm5z'
+    'IGEgTGlzdCBvZiBBY2NvdW50c9IBB3BhZ2VfaWTSAQlwYWdlX3NpemUyIHsicGFnZV9pZCI6ID'
+    'EsICJwYWdlX3NpemUiOiAxMCB9');
+
+@$core.Deprecated('Use listAccountInfoResponseDescriptor instead')
+const ListAccountInfoResponse$json = {
+  '1': 'ListAccountInfoResponse',
+  '2': [
+    {'1': 'account_info', '3': 1, '4': 3, '5': 11, '6': '.pb.AccountInfo', '8': {}, '10': 'accountInfo'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `ListAccountInfoResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List listAccountInfoResponseDescriptor = $convert.base64Decode(
+    'ChdMaXN0QWNjb3VudEluZm9SZXNwb25zZRI3CgxhY2NvdW50X2luZm8YASADKAsyDy5wYi5BY2'
+    'NvdW50SW5mb0IDkkEAUgthY2NvdW50SW5mbzo4kkE1CjMqGExpc3RBY2NvdW50SW5mbyBSZXNw'
+    'b25zZTIXUmV0dXJucyB0aGUgQWNjb3VudEluZm8=');
+
diff --git a/frontend/app/lib/pb/rpc_list_account_info.pbserver.dart b/frontend/app/lib/pb/rpc_list_account_info.pbserver.dart
new file mode 100644
index 0000000..c519635
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_account_info.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_list_account_info.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_list_accounts.pb.dart b/frontend/app/lib/pb/rpc_list_accounts.pb.dart
new file mode 100644
index 0000000..9dd20a2
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_accounts.pb.dart
@@ -0,0 +1,128 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_accounts.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'account.pb.dart' as $2;
+
+class ListAccountsRequest extends $pb.GeneratedMessage {
+  factory ListAccountsRequest({
+    $core.int? pageId,
+    $core.int? pageSize,
+  }) {
+    final $result = create();
+    if (pageId != null) {
+      $result.pageId = pageId;
+    }
+    if (pageSize != null) {
+      $result.pageSize = pageSize;
+    }
+    return $result;
+  }
+  ListAccountsRequest._() : super();
+  factory ListAccountsRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ListAccountsRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListAccountsRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$core.int>(1, _omitFieldNames ? '' : 'pageId', $pb.PbFieldType.OU3)
+    ..a<$core.int>(2, _omitFieldNames ? '' : 'pageSize', $pb.PbFieldType.OU3)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  ListAccountsRequest clone() => ListAccountsRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ListAccountsRequest copyWith(void Function(ListAccountsRequest) updates) => super.copyWith((message) => updates(message as ListAccountsRequest)) as ListAccountsRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static ListAccountsRequest create() => ListAccountsRequest._();
+  ListAccountsRequest createEmptyInstance() => create();
+  static $pb.PbList<ListAccountsRequest> createRepeated() => $pb.PbList<ListAccountsRequest>();
+  @$core.pragma('dart2js:noInline')
+  static ListAccountsRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ListAccountsRequest>(create);
+  static ListAccountsRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.int get pageId => $_getIZ(0);
+  @$pb.TagNumber(1)
+  set pageId($core.int v) { $_setUnsignedInt32(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasPageId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearPageId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.int get pageSize => $_getIZ(1);
+  @$pb.TagNumber(2)
+  set pageSize($core.int v) { $_setUnsignedInt32(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasPageSize() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearPageSize() => clearField(2);
+}
+
+class ListAccountsResponse extends $pb.GeneratedMessage {
+  factory ListAccountsResponse({
+    $core.Iterable<$2.Account>? accounts,
+  }) {
+    final $result = create();
+    if (accounts != null) {
+      $result.accounts.addAll(accounts);
+    }
+    return $result;
+  }
+  ListAccountsResponse._() : super();
+  factory ListAccountsResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ListAccountsResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListAccountsResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..pc<$2.Account>(1, _omitFieldNames ? '' : 'accounts', $pb.PbFieldType.PM, subBuilder: $2.Account.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  ListAccountsResponse clone() => ListAccountsResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ListAccountsResponse copyWith(void Function(ListAccountsResponse) updates) => super.copyWith((message) => updates(message as ListAccountsResponse)) as ListAccountsResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static ListAccountsResponse create() => ListAccountsResponse._();
+  ListAccountsResponse createEmptyInstance() => create();
+  static $pb.PbList<ListAccountsResponse> createRepeated() => $pb.PbList<ListAccountsResponse>();
+  @$core.pragma('dart2js:noInline')
+  static ListAccountsResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ListAccountsResponse>(create);
+  static ListAccountsResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.List<$2.Account> get accounts => $_getList(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_list_accounts.pbenum.dart b/frontend/app/lib/pb/rpc_list_accounts.pbenum.dart
new file mode 100644
index 0000000..d18fe94
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_accounts.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_accounts.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_list_accounts.pbjson.dart b/frontend/app/lib/pb/rpc_list_accounts.pbjson.dart
new file mode 100644
index 0000000..8617af7
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_accounts.pbjson.dart
@@ -0,0 +1,47 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_accounts.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use listAccountsRequestDescriptor instead')
+const ListAccountsRequest$json = {
+  '1': 'ListAccountsRequest',
+  '2': [
+    {'1': 'page_id', '3': 1, '4': 1, '5': 13, '10': 'pageId'},
+    {'1': 'page_size', '3': 2, '4': 1, '5': 13, '10': 'pageSize'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `ListAccountsRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List listAccountsRequestDescriptor = $convert.base64Decode(
+    'ChNMaXN0QWNjb3VudHNSZXF1ZXN0EhcKB3BhZ2VfaWQYASABKA1SBnBhZ2VJZBIbCglwYWdlX3'
+    'NpemUYAiABKA1SCHBhZ2VTaXplOmeSQWQKQCoMTGlzdEFjY291bnRzMhpSZXR1cm5zIGEgTGlz'
+    'dCBvZiBBY2NvdW50c9IBB3BhZ2VfaWTSAQlwYWdlX3NpemUyIHsicGFnZV9pZCI6IDEsICJwYW'
+    'dlX3NpemUiOiAxMCB9');
+
+@$core.Deprecated('Use listAccountsResponseDescriptor instead')
+const ListAccountsResponse$json = {
+  '1': 'ListAccountsResponse',
+  '2': [
+    {'1': 'accounts', '3': 1, '4': 3, '5': 11, '6': '.pb.Account', '8': {}, '10': 'accounts'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `ListAccountsResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List listAccountsResponseDescriptor = $convert.base64Decode(
+    'ChRMaXN0QWNjb3VudHNSZXNwb25zZRIsCghhY2NvdW50cxgBIAMoCzILLnBiLkFjY291bnRCA5'
+    'JBAFIIYWNjb3VudHM6MZJBLgosKhVMaXN0QWNjb3VudHMgUmVzcG9uc2UyE1JldHVybnMgdGhl'
+    'IEFjY291bnQ=');
+
diff --git a/frontend/app/lib/pb/rpc_list_accounts.pbserver.dart b/frontend/app/lib/pb/rpc_list_accounts.pbserver.dart
new file mode 100644
index 0000000..8182a04
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_accounts.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_accounts.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_list_accounts.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_list_payments.pb.dart b/frontend/app/lib/pb/rpc_list_payments.pb.dart
new file mode 100644
index 0000000..a7110a6
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_payments.pb.dart
@@ -0,0 +1,115 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_payments.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'payment.pb.dart' as $3;
+
+class ListPaymentsRequest extends $pb.GeneratedMessage {
+  factory ListPaymentsRequest({
+    $fixnum.Int64? accountId,
+  }) {
+    final $result = create();
+    if (accountId != null) {
+      $result.accountId = accountId;
+    }
+    return $result;
+  }
+  ListPaymentsRequest._() : super();
+  factory ListPaymentsRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ListPaymentsRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListPaymentsRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'accountId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  ListPaymentsRequest clone() => ListPaymentsRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ListPaymentsRequest copyWith(void Function(ListPaymentsRequest) updates) => super.copyWith((message) => updates(message as ListPaymentsRequest)) as ListPaymentsRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static ListPaymentsRequest create() => ListPaymentsRequest._();
+  ListPaymentsRequest createEmptyInstance() => create();
+  static $pb.PbList<ListPaymentsRequest> createRepeated() => $pb.PbList<ListPaymentsRequest>();
+  @$core.pragma('dart2js:noInline')
+  static ListPaymentsRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ListPaymentsRequest>(create);
+  static ListPaymentsRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get accountId => $_getI64(0);
+  @$pb.TagNumber(1)
+  set accountId($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccountId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccountId() => clearField(1);
+}
+
+class ListPaymentsResponse extends $pb.GeneratedMessage {
+  factory ListPaymentsResponse({
+    $core.Iterable<$3.Payment>? payments,
+  }) {
+    final $result = create();
+    if (payments != null) {
+      $result.payments.addAll(payments);
+    }
+    return $result;
+  }
+  ListPaymentsResponse._() : super();
+  factory ListPaymentsResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ListPaymentsResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListPaymentsResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..pc<$3.Payment>(1, _omitFieldNames ? '' : 'payments', $pb.PbFieldType.PM, subBuilder: $3.Payment.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  ListPaymentsResponse clone() => ListPaymentsResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ListPaymentsResponse copyWith(void Function(ListPaymentsResponse) updates) => super.copyWith((message) => updates(message as ListPaymentsResponse)) as ListPaymentsResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static ListPaymentsResponse create() => ListPaymentsResponse._();
+  ListPaymentsResponse createEmptyInstance() => create();
+  static $pb.PbList<ListPaymentsResponse> createRepeated() => $pb.PbList<ListPaymentsResponse>();
+  @$core.pragma('dart2js:noInline')
+  static ListPaymentsResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ListPaymentsResponse>(create);
+  static ListPaymentsResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.List<$3.Payment> get payments => $_getList(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_list_payments.pbenum.dart b/frontend/app/lib/pb/rpc_list_payments.pbenum.dart
new file mode 100644
index 0000000..60975d1
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_payments.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_payments.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_list_payments.pbjson.dart b/frontend/app/lib/pb/rpc_list_payments.pbjson.dart
new file mode 100644
index 0000000..1055398
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_payments.pbjson.dart
@@ -0,0 +1,45 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_payments.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use listPaymentsRequestDescriptor instead')
+const ListPaymentsRequest$json = {
+  '1': 'ListPaymentsRequest',
+  '2': [
+    {'1': 'account_id', '3': 1, '4': 1, '5': 4, '10': 'accountId'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `ListPaymentsRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List listPaymentsRequestDescriptor = $convert.base64Decode(
+    'ChNMaXN0UGF5bWVudHNSZXF1ZXN0Eh0KCmFjY291bnRfaWQYASABKARSCWFjY291bnRJZDpQkk'
+    'FNCjcqDExpc3RQYXltZW50czIaUmV0dXJucyBhIExpc3Qgb2YgUGF5bWVudHPSAQphY2NvdW50'
+    'X2lkMhJ7ImFjY291bnRfaWQiOiAxIH0=');
+
+@$core.Deprecated('Use listPaymentsResponseDescriptor instead')
+const ListPaymentsResponse$json = {
+  '1': 'ListPaymentsResponse',
+  '2': [
+    {'1': 'payments', '3': 1, '4': 3, '5': 11, '6': '.pb.Payment', '8': {}, '10': 'payments'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `ListPaymentsResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List listPaymentsResponseDescriptor = $convert.base64Decode(
+    'ChRMaXN0UGF5bWVudHNSZXNwb25zZRIsCghwYXltZW50cxgBIAMoCzILLnBiLlBheW1lbnRCA5'
+    'JBAFIIcGF5bWVudHM6MZJBLgosKhVMaXN0UGF5bWVudHMgUmVzcG9uc2UyE1JldHVybnMgdGhl'
+    'IFBheW1lbnQ=');
+
diff --git a/frontend/app/lib/pb/rpc_list_payments.pbserver.dart b/frontend/app/lib/pb/rpc_list_payments.pbserver.dart
new file mode 100644
index 0000000..3447e3d
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_payments.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_payments.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_list_payments.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_list_persons.pb.dart b/frontend/app/lib/pb/rpc_list_persons.pb.dart
new file mode 100644
index 0000000..bfac765
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_persons.pb.dart
@@ -0,0 +1,115 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_persons.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'person.pb.dart' as $4;
+
+class ListPersonsRequest extends $pb.GeneratedMessage {
+  factory ListPersonsRequest({
+    $fixnum.Int64? accountId,
+  }) {
+    final $result = create();
+    if (accountId != null) {
+      $result.accountId = accountId;
+    }
+    return $result;
+  }
+  ListPersonsRequest._() : super();
+  factory ListPersonsRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ListPersonsRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListPersonsRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'accountId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  ListPersonsRequest clone() => ListPersonsRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ListPersonsRequest copyWith(void Function(ListPersonsRequest) updates) => super.copyWith((message) => updates(message as ListPersonsRequest)) as ListPersonsRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static ListPersonsRequest create() => ListPersonsRequest._();
+  ListPersonsRequest createEmptyInstance() => create();
+  static $pb.PbList<ListPersonsRequest> createRepeated() => $pb.PbList<ListPersonsRequest>();
+  @$core.pragma('dart2js:noInline')
+  static ListPersonsRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ListPersonsRequest>(create);
+  static ListPersonsRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get accountId => $_getI64(0);
+  @$pb.TagNumber(1)
+  set accountId($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccountId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccountId() => clearField(1);
+}
+
+class ListPersonsResponse extends $pb.GeneratedMessage {
+  factory ListPersonsResponse({
+    $core.Iterable<$4.Person>? persons,
+  }) {
+    final $result = create();
+    if (persons != null) {
+      $result.persons.addAll(persons);
+    }
+    return $result;
+  }
+  ListPersonsResponse._() : super();
+  factory ListPersonsResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ListPersonsResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListPersonsResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..pc<$4.Person>(1, _omitFieldNames ? '' : 'persons', $pb.PbFieldType.PM, subBuilder: $4.Person.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  ListPersonsResponse clone() => ListPersonsResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ListPersonsResponse copyWith(void Function(ListPersonsResponse) updates) => super.copyWith((message) => updates(message as ListPersonsResponse)) as ListPersonsResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static ListPersonsResponse create() => ListPersonsResponse._();
+  ListPersonsResponse createEmptyInstance() => create();
+  static $pb.PbList<ListPersonsResponse> createRepeated() => $pb.PbList<ListPersonsResponse>();
+  @$core.pragma('dart2js:noInline')
+  static ListPersonsResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ListPersonsResponse>(create);
+  static ListPersonsResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.List<$4.Person> get persons => $_getList(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_list_persons.pbenum.dart b/frontend/app/lib/pb/rpc_list_persons.pbenum.dart
new file mode 100644
index 0000000..2b664c4
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_persons.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_persons.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_list_persons.pbjson.dart b/frontend/app/lib/pb/rpc_list_persons.pbjson.dart
new file mode 100644
index 0000000..bc10ba9
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_persons.pbjson.dart
@@ -0,0 +1,45 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_persons.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use listPersonsRequestDescriptor instead')
+const ListPersonsRequest$json = {
+  '1': 'ListPersonsRequest',
+  '2': [
+    {'1': 'account_id', '3': 1, '4': 1, '5': 4, '10': 'accountId'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `ListPersonsRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List listPersonsRequestDescriptor = $convert.base64Decode(
+    'ChJMaXN0UGVyc29uc1JlcXVlc3QSHQoKYWNjb3VudF9pZBgBIAEoBFIJYWNjb3VudElkOk6SQU'
+    'sKNSoLTGlzdFBlcnNvbnMyGVJldHVybnMgYSBMaXN0IG9mIFBlcnNvbnPSAQphY2NvdW50X2lk'
+    'MhJ7ImFjY291bnRfaWQiOiAxIH0=');
+
+@$core.Deprecated('Use listPersonsResponseDescriptor instead')
+const ListPersonsResponse$json = {
+  '1': 'ListPersonsResponse',
+  '2': [
+    {'1': 'persons', '3': 1, '4': 3, '5': 11, '6': '.pb.Person', '8': {}, '10': 'persons'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `ListPersonsResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List listPersonsResponseDescriptor = $convert.base64Decode(
+    'ChNMaXN0UGVyc29uc1Jlc3BvbnNlEikKB3BlcnNvbnMYASADKAsyCi5wYi5QZXJzb25CA5JBAF'
+    'IHcGVyc29uczovkkEsCioqFExpc3RQZXJzb25zIFJlc3BvbnNlMhJSZXR1cm5zIHRoZSBQZXJz'
+    'b24=');
+
diff --git a/frontend/app/lib/pb/rpc_list_persons.pbserver.dart b/frontend/app/lib/pb/rpc_list_persons.pbserver.dart
new file mode 100644
index 0000000..f7e01f9
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_persons.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_persons.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_list_persons.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pb.dart b/frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pb.dart
new file mode 100644
index 0000000..61fbff1
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pb.dart
@@ -0,0 +1,115 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_returns_log_by_person_id.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'returns_log.pb.dart' as $5;
+
+class ListReturnsLogRequest extends $pb.GeneratedMessage {
+  factory ListReturnsLogRequest({
+    $fixnum.Int64? personId,
+  }) {
+    final $result = create();
+    if (personId != null) {
+      $result.personId = personId;
+    }
+    return $result;
+  }
+  ListReturnsLogRequest._() : super();
+  factory ListReturnsLogRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ListReturnsLogRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListReturnsLogRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'personId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  ListReturnsLogRequest clone() => ListReturnsLogRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ListReturnsLogRequest copyWith(void Function(ListReturnsLogRequest) updates) => super.copyWith((message) => updates(message as ListReturnsLogRequest)) as ListReturnsLogRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static ListReturnsLogRequest create() => ListReturnsLogRequest._();
+  ListReturnsLogRequest createEmptyInstance() => create();
+  static $pb.PbList<ListReturnsLogRequest> createRepeated() => $pb.PbList<ListReturnsLogRequest>();
+  @$core.pragma('dart2js:noInline')
+  static ListReturnsLogRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ListReturnsLogRequest>(create);
+  static ListReturnsLogRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get personId => $_getI64(0);
+  @$pb.TagNumber(1)
+  set personId($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasPersonId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearPersonId() => clearField(1);
+}
+
+class ListReturnsLogResponse extends $pb.GeneratedMessage {
+  factory ListReturnsLogResponse({
+    $core.Iterable<$5.ReturnsLog>? returnsLog,
+  }) {
+    final $result = create();
+    if (returnsLog != null) {
+      $result.returnsLog.addAll(returnsLog);
+    }
+    return $result;
+  }
+  ListReturnsLogResponse._() : super();
+  factory ListReturnsLogResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ListReturnsLogResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListReturnsLogResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..pc<$5.ReturnsLog>(1, _omitFieldNames ? '' : 'returnsLog', $pb.PbFieldType.PM, subBuilder: $5.ReturnsLog.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  ListReturnsLogResponse clone() => ListReturnsLogResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ListReturnsLogResponse copyWith(void Function(ListReturnsLogResponse) updates) => super.copyWith((message) => updates(message as ListReturnsLogResponse)) as ListReturnsLogResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static ListReturnsLogResponse create() => ListReturnsLogResponse._();
+  ListReturnsLogResponse createEmptyInstance() => create();
+  static $pb.PbList<ListReturnsLogResponse> createRepeated() => $pb.PbList<ListReturnsLogResponse>();
+  @$core.pragma('dart2js:noInline')
+  static ListReturnsLogResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ListReturnsLogResponse>(create);
+  static ListReturnsLogResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.List<$5.ReturnsLog> get returnsLog => $_getList(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pbenum.dart b/frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pbenum.dart
new file mode 100644
index 0000000..4a25147
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_returns_log_by_person_id.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pbjson.dart b/frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pbjson.dart
new file mode 100644
index 0000000..925ac54
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pbjson.dart
@@ -0,0 +1,45 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_returns_log_by_person_id.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use listReturnsLogRequestDescriptor instead')
+const ListReturnsLogRequest$json = {
+  '1': 'ListReturnsLogRequest',
+  '2': [
+    {'1': 'person_id', '3': 1, '4': 1, '5': 4, '10': 'personId'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `ListReturnsLogRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List listReturnsLogRequestDescriptor = $convert.base64Decode(
+    'ChVMaXN0UmV0dXJuc0xvZ1JlcXVlc3QSGwoJcGVyc29uX2lkGAEgASgEUghwZXJzb25JZDpSkk'
+    'FPCjoqDkxpc3RSZXR1cm5zTG9nMhxSZXR1cm5zIGEgTGlzdCBvZiBSZXR1cm5zTG9n0gEJcGVy'
+    'c29uX2lkMhF7InBlcnNvbl9pZCI6IDEgfQ==');
+
+@$core.Deprecated('Use listReturnsLogResponseDescriptor instead')
+const ListReturnsLogResponse$json = {
+  '1': 'ListReturnsLogResponse',
+  '2': [
+    {'1': 'returns_log', '3': 1, '4': 3, '5': 11, '6': '.pb.ReturnsLog', '8': {}, '10': 'returnsLog'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `ListReturnsLogResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List listReturnsLogResponseDescriptor = $convert.base64Decode(
+    'ChZMaXN0UmV0dXJuc0xvZ1Jlc3BvbnNlEjQKC3JldHVybnNfbG9nGAEgAygLMg4ucGIuUmV0dX'
+    'Juc0xvZ0IDkkEAUgpyZXR1cm5zTG9nOjaSQTMKMSoXTGlzdFJldHVybnNMb2cgUmVzcG9uc2Uy'
+    'FlJldHVybnMgdGhlIFJldHVybnNMb2c=');
+
diff --git a/frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pbserver.dart b/frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pbserver.dart
new file mode 100644
index 0000000..8498af0
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_returns_log_by_person_id.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_list_returns_log_by_person_id.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_list_sessions.pb.dart b/frontend/app/lib/pb/rpc_list_sessions.pb.dart
new file mode 100644
index 0000000..1a9f5af
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_sessions.pb.dart
@@ -0,0 +1,115 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_sessions.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'session.pb.dart' as $6;
+
+class ListSessionsRequest extends $pb.GeneratedMessage {
+  factory ListSessionsRequest({
+    $fixnum.Int64? accountId,
+  }) {
+    final $result = create();
+    if (accountId != null) {
+      $result.accountId = accountId;
+    }
+    return $result;
+  }
+  ListSessionsRequest._() : super();
+  factory ListSessionsRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ListSessionsRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListSessionsRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'accountId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  ListSessionsRequest clone() => ListSessionsRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ListSessionsRequest copyWith(void Function(ListSessionsRequest) updates) => super.copyWith((message) => updates(message as ListSessionsRequest)) as ListSessionsRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static ListSessionsRequest create() => ListSessionsRequest._();
+  ListSessionsRequest createEmptyInstance() => create();
+  static $pb.PbList<ListSessionsRequest> createRepeated() => $pb.PbList<ListSessionsRequest>();
+  @$core.pragma('dart2js:noInline')
+  static ListSessionsRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ListSessionsRequest>(create);
+  static ListSessionsRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get accountId => $_getI64(0);
+  @$pb.TagNumber(1)
+  set accountId($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccountId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccountId() => clearField(1);
+}
+
+class ListSessionsResponse extends $pb.GeneratedMessage {
+  factory ListSessionsResponse({
+    $core.Iterable<$6.Session>? sessions,
+  }) {
+    final $result = create();
+    if (sessions != null) {
+      $result.sessions.addAll(sessions);
+    }
+    return $result;
+  }
+  ListSessionsResponse._() : super();
+  factory ListSessionsResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory ListSessionsResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListSessionsResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..pc<$6.Session>(1, _omitFieldNames ? '' : 'sessions', $pb.PbFieldType.PM, subBuilder: $6.Session.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  ListSessionsResponse clone() => ListSessionsResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  ListSessionsResponse copyWith(void Function(ListSessionsResponse) updates) => super.copyWith((message) => updates(message as ListSessionsResponse)) as ListSessionsResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static ListSessionsResponse create() => ListSessionsResponse._();
+  ListSessionsResponse createEmptyInstance() => create();
+  static $pb.PbList<ListSessionsResponse> createRepeated() => $pb.PbList<ListSessionsResponse>();
+  @$core.pragma('dart2js:noInline')
+  static ListSessionsResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<ListSessionsResponse>(create);
+  static ListSessionsResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.List<$6.Session> get sessions => $_getList(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_list_sessions.pbenum.dart b/frontend/app/lib/pb/rpc_list_sessions.pbenum.dart
new file mode 100644
index 0000000..1c4fe8a
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_sessions.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_sessions.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_list_sessions.pbjson.dart b/frontend/app/lib/pb/rpc_list_sessions.pbjson.dart
new file mode 100644
index 0000000..e86eae8
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_sessions.pbjson.dart
@@ -0,0 +1,45 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_sessions.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use listSessionsRequestDescriptor instead')
+const ListSessionsRequest$json = {
+  '1': 'ListSessionsRequest',
+  '2': [
+    {'1': 'account_id', '3': 1, '4': 1, '5': 4, '8': {}, '10': 'accountId'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `ListSessionsRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List listSessionsRequestDescriptor = $convert.base64Decode(
+    'ChNMaXN0U2Vzc2lvbnNSZXF1ZXN0Ei0KCmFjY291bnRfaWQYASABKARCDpJBC0oBMaICBWludD'
+    'Y0UglhY2NvdW50SWQ6UpJBTwo3KgxMaXN0U2Vzc2lvbnMyGlJldHVybnMgYSBMaXN0IG9mIEFj'
+    'Y291bnRz0gEKYWNjb3VudF9pZDIUeyJhY2NvdW50X2lkIjogIjEiIH0=');
+
+@$core.Deprecated('Use listSessionsResponseDescriptor instead')
+const ListSessionsResponse$json = {
+  '1': 'ListSessionsResponse',
+  '2': [
+    {'1': 'sessions', '3': 1, '4': 3, '5': 11, '6': '.pb.Session', '8': {}, '10': 'sessions'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `ListSessionsResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List listSessionsResponseDescriptor = $convert.base64Decode(
+    'ChRMaXN0U2Vzc2lvbnNSZXNwb25zZRIsCghzZXNzaW9ucxgBIAMoCzILLnBiLlNlc3Npb25CA5'
+    'JBAFIIc2Vzc2lvbnM6MpJBLwotKhVMaXN0U2Vzc2lvbnMgUmVzcG9uc2UyFFJldHVybnMgdGhl'
+    'IFNlc3Npb25z');
+
diff --git a/frontend/app/lib/pb/rpc_list_sessions.pbserver.dart b/frontend/app/lib/pb/rpc_list_sessions.pbserver.dart
new file mode 100644
index 0000000..e4bcfda
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_list_sessions.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_list_sessions.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_list_sessions.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_login.pb.dart b/frontend/app/lib/pb/rpc_login.pb.dart
new file mode 100644
index 0000000..30ded55
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_login.pb.dart
@@ -0,0 +1,209 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_login.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'google/protobuf/timestamp.pb.dart' as $0;
+
+class LoginRequest extends $pb.GeneratedMessage {
+  factory LoginRequest({
+    $core.String? email,
+    $core.String? password,
+  }) {
+    final $result = create();
+    if (email != null) {
+      $result.email = email;
+    }
+    if (password != null) {
+      $result.password = password;
+    }
+    return $result;
+  }
+  LoginRequest._() : super();
+  factory LoginRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory LoginRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'LoginRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOS(1, _omitFieldNames ? '' : 'email')
+    ..aOS(2, _omitFieldNames ? '' : 'password')
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  LoginRequest clone() => LoginRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  LoginRequest copyWith(void Function(LoginRequest) updates) => super.copyWith((message) => updates(message as LoginRequest)) as LoginRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static LoginRequest create() => LoginRequest._();
+  LoginRequest createEmptyInstance() => create();
+  static $pb.PbList<LoginRequest> createRepeated() => $pb.PbList<LoginRequest>();
+  @$core.pragma('dart2js:noInline')
+  static LoginRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<LoginRequest>(create);
+  static LoginRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get email => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set email($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasEmail() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearEmail() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.String get password => $_getSZ(1);
+  @$pb.TagNumber(2)
+  set password($core.String v) { $_setString(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasPassword() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearPassword() => clearField(2);
+}
+
+class LoginResponse extends $pb.GeneratedMessage {
+  factory LoginResponse({
+    $core.String? sessionId,
+    $core.String? accessToken,
+    $0.Timestamp? accessTokenExpiresAt,
+    $core.String? refreshToken,
+    $0.Timestamp? refreshTokenExpiresAt,
+    $fixnum.Int64? accountId,
+  }) {
+    final $result = create();
+    if (sessionId != null) {
+      $result.sessionId = sessionId;
+    }
+    if (accessToken != null) {
+      $result.accessToken = accessToken;
+    }
+    if (accessTokenExpiresAt != null) {
+      $result.accessTokenExpiresAt = accessTokenExpiresAt;
+    }
+    if (refreshToken != null) {
+      $result.refreshToken = refreshToken;
+    }
+    if (refreshTokenExpiresAt != null) {
+      $result.refreshTokenExpiresAt = refreshTokenExpiresAt;
+    }
+    if (accountId != null) {
+      $result.accountId = accountId;
+    }
+    return $result;
+  }
+  LoginResponse._() : super();
+  factory LoginResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory LoginResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'LoginResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOS(1, _omitFieldNames ? '' : 'sessionId')
+    ..aOS(2, _omitFieldNames ? '' : 'accessToken')
+    ..aOM<$0.Timestamp>(3, _omitFieldNames ? '' : 'accessTokenExpiresAt', subBuilder: $0.Timestamp.create)
+    ..aOS(4, _omitFieldNames ? '' : 'refreshToken')
+    ..aOM<$0.Timestamp>(5, _omitFieldNames ? '' : 'refreshTokenExpiresAt', subBuilder: $0.Timestamp.create)
+    ..a<$fixnum.Int64>(6, _omitFieldNames ? '' : 'accountId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  LoginResponse clone() => LoginResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  LoginResponse copyWith(void Function(LoginResponse) updates) => super.copyWith((message) => updates(message as LoginResponse)) as LoginResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static LoginResponse create() => LoginResponse._();
+  LoginResponse createEmptyInstance() => create();
+  static $pb.PbList<LoginResponse> createRepeated() => $pb.PbList<LoginResponse>();
+  @$core.pragma('dart2js:noInline')
+  static LoginResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<LoginResponse>(create);
+  static LoginResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get sessionId => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set sessionId($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasSessionId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearSessionId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.String get accessToken => $_getSZ(1);
+  @$pb.TagNumber(2)
+  set accessToken($core.String v) { $_setString(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasAccessToken() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearAccessToken() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $0.Timestamp get accessTokenExpiresAt => $_getN(2);
+  @$pb.TagNumber(3)
+  set accessTokenExpiresAt($0.Timestamp v) { setField(3, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasAccessTokenExpiresAt() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearAccessTokenExpiresAt() => clearField(3);
+  @$pb.TagNumber(3)
+  $0.Timestamp ensureAccessTokenExpiresAt() => $_ensure(2);
+
+  @$pb.TagNumber(4)
+  $core.String get refreshToken => $_getSZ(3);
+  @$pb.TagNumber(4)
+  set refreshToken($core.String v) { $_setString(3, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasRefreshToken() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearRefreshToken() => clearField(4);
+
+  @$pb.TagNumber(5)
+  $0.Timestamp get refreshTokenExpiresAt => $_getN(4);
+  @$pb.TagNumber(5)
+  set refreshTokenExpiresAt($0.Timestamp v) { setField(5, v); }
+  @$pb.TagNumber(5)
+  $core.bool hasRefreshTokenExpiresAt() => $_has(4);
+  @$pb.TagNumber(5)
+  void clearRefreshTokenExpiresAt() => clearField(5);
+  @$pb.TagNumber(5)
+  $0.Timestamp ensureRefreshTokenExpiresAt() => $_ensure(4);
+
+  @$pb.TagNumber(6)
+  $fixnum.Int64 get accountId => $_getI64(5);
+  @$pb.TagNumber(6)
+  set accountId($fixnum.Int64 v) { $_setInt64(5, v); }
+  @$pb.TagNumber(6)
+  $core.bool hasAccountId() => $_has(5);
+  @$pb.TagNumber(6)
+  void clearAccountId() => clearField(6);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_login.pbenum.dart b/frontend/app/lib/pb/rpc_login.pbenum.dart
new file mode 100644
index 0000000..4b431da
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_login.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_login.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_login.pbjson.dart b/frontend/app/lib/pb/rpc_login.pbjson.dart
new file mode 100644
index 0000000..800e0ac
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_login.pbjson.dart
@@ -0,0 +1,70 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_login.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use loginRequestDescriptor instead')
+const LoginRequest$json = {
+  '1': 'LoginRequest',
+  '2': [
+    {'1': 'email', '3': 1, '4': 1, '5': 9, '8': {}, '10': 'email'},
+    {'1': 'password', '3': 2, '4': 1, '5': 9, '8': {}, '10': 'password'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `LoginRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List loginRequestDescriptor = $convert.base64Decode(
+    'CgxMb2dpblJlcXVlc3QSMQoFZW1haWwYASABKAlCG5JBGEoWImpvaG4uZG9lQGV4YW1wbGUuY2'
+    '9tIlIFZW1haWwSQwoIcGFzc3dvcmQYAiABKAlCJ5JBJEoXIk1heVRoZUZvcmNlQmVXaXRoWW91'
+    'ISKiAghwYXNzd29yZFIIcGFzc3dvcmQ6eZJBdgosKgVMb2dpbjIQTG9naW4gYW4gQWNjb3VudN'
+    'IBBWVtYWls0gEIcGFzc3dvcmQyRnsiZW1haWwiOiAiam9obi5kb2VAZXhhbXBsZS5jb20iLCAi'
+    'cGFzc3dvcmQiOiAiTWF5VGhlRm9yY2VCZVdpdGhZb3UhIn0=');
+
+@$core.Deprecated('Use loginResponseDescriptor instead')
+const LoginResponse$json = {
+  '1': 'LoginResponse',
+  '2': [
+    {'1': 'session_id', '3': 1, '4': 1, '5': 9, '8': {}, '10': 'sessionId'},
+    {'1': 'access_token', '3': 2, '4': 1, '5': 9, '8': {}, '10': 'accessToken'},
+    {'1': 'access_token_expires_at', '3': 3, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '10': 'accessTokenExpiresAt'},
+    {'1': 'refresh_token', '3': 4, '4': 1, '5': 9, '8': {}, '10': 'refreshToken'},
+    {'1': 'refresh_token_expires_at', '3': 5, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '10': 'refreshTokenExpiresAt'},
+    {'1': 'account_id', '3': 6, '4': 1, '5': 4, '8': {}, '10': 'accountId'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `LoginResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List loginResponseDescriptor = $convert.base64Decode(
+    'Cg1Mb2dpblJlc3BvbnNlElEKCnNlc3Npb25faWQYASABKAlCMpJBL0omIjVlMWQ2N2RhLTdjOW'
+    'ItNDM2NS1hNGQ1LTNjYzBhMDUxMjQxZSKiAgR1dWlkUglzZXNzaW9uSWQS6QIKDGFjY2Vzc190'
+    'b2tlbhgCIAEoCULFApJBwQJKvgIidjQucHVibGljLmV5SmxiV0ZwYkNJNkltRXlRR0l1WkdVaU'
+    'xDSmxlSEFpT2lJeU1ESXpMVEV3TFRBMVZEQXhPakUzT2pBNUt6QXlPakF3SWl3aWFXRjBJam9p'
+    'TWpBeU15MHhNQzB3TlZRd01Ub3dNam93T1Nzd01qb3dNQ0lzSW1sa0lqb2laamxoTWpFMk9XUX'
+    'RNV1l4WVMwMFlUaGlMVGd6WldFdE56a3hNelk1WWpZM1ptWXhJaXdpYm1KbUlqb2lNakF5TXkw'
+    'eE1DMHdOVlF3TVRvd01qb3dPU3N3TWpvd01DSjlBaDBiVmJ4OVMxTFItcGY4aExXVlJRUFVmSz'
+    'l6ckhadkE3QXBKNWFaWHdoQTdIMWota0hoY2NCak9BR1lYWlFULXRzN0pxM1NKbHpvNXZ0VWpH'
+    'QnREZyJSC2FjY2Vzc1Rva2VuElEKF2FjY2Vzc190b2tlbl9leHBpcmVzX2F0GAMgASgLMhouZ2'
+    '9vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcFIUYWNjZXNzVG9rZW5FeHBpcmVzQXQS6wIKDXJlZnJl'
+    'c2hfdG9rZW4YBCABKAlCxQKSQcECSr4CInY0LnB1YmxpYy5leUpsYldGcGJDSTZJbUV5UUdJdV'
+    'pHVWlMQ0psZUhBaU9pSXlNREl6TFRFd0xUQTJWREF4T2pBeU9qQTVLekF5T2pBd0lpd2lhV0Yw'
+    'SWpvaU1qQXlNeTB4TUMwd05WUXdNVG93TWpvd09Tc3dNam93TUNJc0ltbGtJam9pTldVeFpEWT'
+    'NaR0V0TjJNNVlpMDBNelkxTFdFMFpEVXRNMk5qTUdFd05URXlOREZsSWl3aWJtSm1Jam9pTWpB'
+    'eU15MHhNQzB3TlZRd01Ub3dNam93T1Nzd01qb3dNQ0o5Qm9YMzZ3MHBvMXZ2SFNqc0JQX0tXZU'
+    'Z4VjF4UmJRYXlxYkp1SW9LMmpLcXkxQnQyUm9IeUpiTG9DRU8xNUNSVDVEblE2UDBBSGxCempz'
+    'WHQ2MWFERHciUgxyZWZyZXNoVG9rZW4SUwoYcmVmcmVzaF90b2tlbl9leHBpcmVzX2F0GAUgAS'
+    'gLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcFIVcmVmcmVzaFRva2VuRXhwaXJlc0F0EicK'
+    'CmFjY291bnRfaWQYBiABKARCCJJBBUoDIjEiUglhY2NvdW50SWQ6FZJBEgoQKg5Mb2dpbiBSZX'
+    'Nwb25zZQ==');
+
diff --git a/frontend/app/lib/pb/rpc_login.pbserver.dart b/frontend/app/lib/pb/rpc_login.pbserver.dart
new file mode 100644
index 0000000..c90dce9
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_login.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_login.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_login.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_refresh_token.pb.dart b/frontend/app/lib/pb/rpc_refresh_token.pb.dart
new file mode 100644
index 0000000..a7780c3
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_refresh_token.pb.dart
@@ -0,0 +1,136 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_refresh_token.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'google/protobuf/timestamp.pb.dart' as $0;
+
+class RefreshTokenRequest extends $pb.GeneratedMessage {
+  factory RefreshTokenRequest({
+    $core.String? refreshToken,
+  }) {
+    final $result = create();
+    if (refreshToken != null) {
+      $result.refreshToken = refreshToken;
+    }
+    return $result;
+  }
+  RefreshTokenRequest._() : super();
+  factory RefreshTokenRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory RefreshTokenRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'RefreshTokenRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOS(1, _omitFieldNames ? '' : 'refreshToken')
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  RefreshTokenRequest clone() => RefreshTokenRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  RefreshTokenRequest copyWith(void Function(RefreshTokenRequest) updates) => super.copyWith((message) => updates(message as RefreshTokenRequest)) as RefreshTokenRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static RefreshTokenRequest create() => RefreshTokenRequest._();
+  RefreshTokenRequest createEmptyInstance() => create();
+  static $pb.PbList<RefreshTokenRequest> createRepeated() => $pb.PbList<RefreshTokenRequest>();
+  @$core.pragma('dart2js:noInline')
+  static RefreshTokenRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<RefreshTokenRequest>(create);
+  static RefreshTokenRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get refreshToken => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set refreshToken($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasRefreshToken() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearRefreshToken() => clearField(1);
+}
+
+class RefreshTokenResponse extends $pb.GeneratedMessage {
+  factory RefreshTokenResponse({
+    $core.String? accessToken,
+    $0.Timestamp? accessTokenExpiresAt,
+  }) {
+    final $result = create();
+    if (accessToken != null) {
+      $result.accessToken = accessToken;
+    }
+    if (accessTokenExpiresAt != null) {
+      $result.accessTokenExpiresAt = accessTokenExpiresAt;
+    }
+    return $result;
+  }
+  RefreshTokenResponse._() : super();
+  factory RefreshTokenResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory RefreshTokenResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'RefreshTokenResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOS(1, _omitFieldNames ? '' : 'accessToken')
+    ..aOM<$0.Timestamp>(2, _omitFieldNames ? '' : 'accessTokenExpiresAt', subBuilder: $0.Timestamp.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  RefreshTokenResponse clone() => RefreshTokenResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  RefreshTokenResponse copyWith(void Function(RefreshTokenResponse) updates) => super.copyWith((message) => updates(message as RefreshTokenResponse)) as RefreshTokenResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static RefreshTokenResponse create() => RefreshTokenResponse._();
+  RefreshTokenResponse createEmptyInstance() => create();
+  static $pb.PbList<RefreshTokenResponse> createRepeated() => $pb.PbList<RefreshTokenResponse>();
+  @$core.pragma('dart2js:noInline')
+  static RefreshTokenResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<RefreshTokenResponse>(create);
+  static RefreshTokenResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get accessToken => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set accessToken($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccessToken() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccessToken() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $0.Timestamp get accessTokenExpiresAt => $_getN(1);
+  @$pb.TagNumber(2)
+  set accessTokenExpiresAt($0.Timestamp v) { setField(2, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasAccessTokenExpiresAt() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearAccessTokenExpiresAt() => clearField(2);
+  @$pb.TagNumber(2)
+  $0.Timestamp ensureAccessTokenExpiresAt() => $_ensure(1);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_refresh_token.pbenum.dart b/frontend/app/lib/pb/rpc_refresh_token.pbenum.dart
new file mode 100644
index 0000000..7499f0c
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_refresh_token.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_refresh_token.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_refresh_token.pbjson.dart b/frontend/app/lib/pb/rpc_refresh_token.pbjson.dart
new file mode 100644
index 0000000..875d1b7
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_refresh_token.pbjson.dart
@@ -0,0 +1,72 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_refresh_token.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use refreshTokenRequestDescriptor instead')
+const RefreshTokenRequest$json = {
+  '1': 'RefreshTokenRequest',
+  '2': [
+    {'1': 'refresh_token', '3': 1, '4': 1, '5': 9, '8': {}, '10': 'refreshToken'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `RefreshTokenRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List refreshTokenRequestDescriptor = $convert.base64Decode(
+    'ChNSZWZyZXNoVG9rZW5SZXF1ZXN0EvoCCg1yZWZyZXNoX3Rva2VuGAEgASgJQtQCkkHQAioNUm'
+    'VmcmVzaCBUb2tlbkq+AiJ2NC5wdWJsaWMuZXlKbGJXRnBiQ0k2SW1FeVFHSXVaR1VpTENKbGVI'
+    'QWlPaUl5TURJekxURXdMVEEyVkRBeE9qQXlPakE1S3pBeU9qQXdJaXdpYVdGMElqb2lNakF5TX'
+    'kweE1DMHdOVlF3TVRvd01qb3dPU3N3TWpvd01DSXNJbWxrSWpvaU5XVXhaRFkzWkdFdE4yTTVZ'
+    'aTAwTXpZMUxXRTBaRFV0TTJOak1HRXdOVEV5TkRGbElpd2libUptSWpvaU1qQXlNeTB4TUMwd0'
+    '5WUXdNVG93TWpvd09Tc3dNam93TUNKOUJvWDM2dzBwbzF2dkhTanNCUF9LV2VGeFYxeFJiUWF5'
+    'cWJKdUlvSzJqS3F5MUJ0MlJvSHlKYkxvQ0VPMTVDUlQ1RG5RNlAwQUhsQnpqc1h0NjFhRER3Il'
+    'IMcmVmcmVzaFRva2VuOrkDkkG1AwpfKhVSZWZyZXNoIFRva2VuIFJlcXVlc3QyNkdldCBhIG5l'
+    'dyBBY2Nlc3MgVG9rZW4gYnkgc3VibWl0dGluZyB0aGUgUmVmcmVzaCBUb2tlbtIBDXJlZnJlc2'
+    'hfdG9rZW4y0QJ7InJlZnJlc2hfdG9rZW4iOiAidjQucHVibGljLmV5SmxiV0ZwYkNJNkltRXlR'
+    'R0l1WkdVaUxDSmxlSEFpT2lJeU1ESXpMVEV3TFRBMlZEQXhPakF5T2pBNUt6QXlPakF3SWl3aW'
+    'FXRjBJam9pTWpBeU15MHhNQzB3TlZRd01Ub3dNam93T1Nzd01qb3dNQ0lzSW1sa0lqb2lOV1V4'
+    'WkRZM1pHRXROMk01WWkwME16WTFMV0UwWkRVdE0yTmpNR0V3TlRFeU5ERmxJaXdpYm1KbUlqb2'
+    'lNakF5TXkweE1DMHdOVlF3TVRvd01qb3dPU3N3TWpvd01DSjlCb1gzNncwcG8xdnZIU2pzQlBf'
+    'S1dlRnhWMXhSYlFheXFiSnVJb0syaktxeTFCdDJSb0h5SmJMb0NFTzE1Q1JUNURuUTZQMEFIbE'
+    'J6anNYdDYxYUREdyJ9');
+
+@$core.Deprecated('Use refreshTokenResponseDescriptor instead')
+const RefreshTokenResponse$json = {
+  '1': 'RefreshTokenResponse',
+  '2': [
+    {'1': 'access_token', '3': 1, '4': 1, '5': 9, '8': {}, '10': 'accessToken'},
+    {'1': 'access_token_expires_at', '3': 2, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '10': 'accessTokenExpiresAt'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `RefreshTokenResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List refreshTokenResponseDescriptor = $convert.base64Decode(
+    'ChRSZWZyZXNoVG9rZW5SZXNwb25zZRL3AgoMYWNjZXNzX3Rva2VuGAEgASgJQtMCkkHPAioMQW'
+    'NjZXNzIFRva2VuSr4CInY0LnB1YmxpYy5leUpsYldGcGJDSTZJbUV5UUdJdVpHVWlMQ0psZUhB'
+    'aU9pSXlNREl6TFRFd0xUQTFWREF4T2pFM09qQTVLekF5T2pBd0lpd2lhV0YwSWpvaU1qQXlNeT'
+    'B4TUMwd05WUXdNVG93TWpvd09Tc3dNam93TUNJc0ltbGtJam9pWmpsaE1qRTJPV1F0TVdZeFlT'
+    'MDBZVGhpTFRnelpXRXROemt4TXpZNVlqWTNabVl4SWl3aWJtSm1Jam9pTWpBeU15MHhNQzB3Tl'
+    'ZRd01Ub3dNam93T1Nzd01qb3dNQ0o5QWgwYlZieDlTMUxSLXBmOGhMV1ZSUVBVZks5enJIWnZB'
+    'N0FwSjVhWlh3aEE3SDFqLWtIaGNjQmpPQUdZWFpRVC10czdKcTNTSmx6bzV2dFVqR0J0RGciUg'
+    'thY2Nlc3NUb2tlbhJRChdhY2Nlc3NfdG9rZW5fZXhwaXJlc19hdBgCIAEoCzIaLmdvb2dsZS5w'
+    'cm90b2J1Zi5UaW1lc3RhbXBSFGFjY2Vzc1Rva2VuRXhwaXJlc0F0OvECkkHtAgoYKhZSZWZyZX'
+    'NoIFRva2VuIFJlc3BvbnNlMtACeyJhY2Nlc3NfdG9rZW4iOiAidjQucHVibGljLmV5SmxiV0Zw'
+    'YkNJNkltRXlRR0l1WkdVaUxDSmxlSEFpT2lJeU1ESXpMVEV3TFRBMVZEQXhPakUzT2pBNUt6QX'
+    'lPakF3SWl3aWFXRjBJam9pTWpBeU15MHhNQzB3TlZRd01Ub3dNam93T1Nzd01qb3dNQ0lzSW1s'
+    'a0lqb2laamxoTWpFMk9XUXRNV1l4WVMwMFlUaGlMVGd6WldFdE56a3hNelk1WWpZM1ptWXhJaX'
+    'dpYm1KbUlqb2lNakF5TXkweE1DMHdOVlF3TVRvd01qb3dPU3N3TWpvd01DSjlBaDBiVmJ4OVMx'
+    'TFItcGY4aExXVlJRUFVmSzl6ckhadkE3QXBKNWFaWHdoQTdIMWota0hoY2NCak9BR1lYWlFULX'
+    'RzN0pxM1NKbHpvNXZ0VWpHQnREZyJ9');
+
diff --git a/frontend/app/lib/pb/rpc_refresh_token.pbserver.dart b/frontend/app/lib/pb/rpc_refresh_token.pbserver.dart
new file mode 100644
index 0000000..df1bd59
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_refresh_token.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_refresh_token.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_refresh_token.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_update_account.pb.dart b/frontend/app/lib/pb/rpc_update_account.pb.dart
new file mode 100644
index 0000000..049177b
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_account.pb.dart
@@ -0,0 +1,151 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_account.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'account.pb.dart' as $2;
+
+class UpdateAccountRequest extends $pb.GeneratedMessage {
+  factory UpdateAccountRequest({
+    $fixnum.Int64? accountId,
+    $core.String? email,
+    $core.String? password,
+  }) {
+    final $result = create();
+    if (accountId != null) {
+      $result.accountId = accountId;
+    }
+    if (email != null) {
+      $result.email = email;
+    }
+    if (password != null) {
+      $result.password = password;
+    }
+    return $result;
+  }
+  UpdateAccountRequest._() : super();
+  factory UpdateAccountRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory UpdateAccountRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UpdateAccountRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'accountId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..aOS(2, _omitFieldNames ? '' : 'email')
+    ..aOS(3, _omitFieldNames ? '' : 'password')
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  UpdateAccountRequest clone() => UpdateAccountRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  UpdateAccountRequest copyWith(void Function(UpdateAccountRequest) updates) => super.copyWith((message) => updates(message as UpdateAccountRequest)) as UpdateAccountRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static UpdateAccountRequest create() => UpdateAccountRequest._();
+  UpdateAccountRequest createEmptyInstance() => create();
+  static $pb.PbList<UpdateAccountRequest> createRepeated() => $pb.PbList<UpdateAccountRequest>();
+  @$core.pragma('dart2js:noInline')
+  static UpdateAccountRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<UpdateAccountRequest>(create);
+  static UpdateAccountRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get accountId => $_getI64(0);
+  @$pb.TagNumber(1)
+  set accountId($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccountId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccountId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.String get email => $_getSZ(1);
+  @$pb.TagNumber(2)
+  set email($core.String v) { $_setString(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasEmail() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearEmail() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $core.String get password => $_getSZ(2);
+  @$pb.TagNumber(3)
+  set password($core.String v) { $_setString(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasPassword() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearPassword() => clearField(3);
+}
+
+class UpdateAccountResponse extends $pb.GeneratedMessage {
+  factory UpdateAccountResponse({
+    $2.Account? account,
+  }) {
+    final $result = create();
+    if (account != null) {
+      $result.account = account;
+    }
+    return $result;
+  }
+  UpdateAccountResponse._() : super();
+  factory UpdateAccountResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory UpdateAccountResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UpdateAccountResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOM<$2.Account>(1, _omitFieldNames ? '' : 'account', subBuilder: $2.Account.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  UpdateAccountResponse clone() => UpdateAccountResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  UpdateAccountResponse copyWith(void Function(UpdateAccountResponse) updates) => super.copyWith((message) => updates(message as UpdateAccountResponse)) as UpdateAccountResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static UpdateAccountResponse create() => UpdateAccountResponse._();
+  UpdateAccountResponse createEmptyInstance() => create();
+  static $pb.PbList<UpdateAccountResponse> createRepeated() => $pb.PbList<UpdateAccountResponse>();
+  @$core.pragma('dart2js:noInline')
+  static UpdateAccountResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<UpdateAccountResponse>(create);
+  static UpdateAccountResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $2.Account get account => $_getN(0);
+  @$pb.TagNumber(1)
+  set account($2.Account v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccount() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccount() => clearField(1);
+  @$pb.TagNumber(1)
+  $2.Account ensureAccount() => $_ensure(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_update_account.pbenum.dart b/frontend/app/lib/pb/rpc_update_account.pbenum.dart
new file mode 100644
index 0000000..3001d6b
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_account.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_account.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_update_account.pbjson.dart b/frontend/app/lib/pb/rpc_update_account.pbjson.dart
new file mode 100644
index 0000000..dbf5c0d
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_account.pbjson.dart
@@ -0,0 +1,53 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_account.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use updateAccountRequestDescriptor instead')
+const UpdateAccountRequest$json = {
+  '1': 'UpdateAccountRequest',
+  '2': [
+    {'1': 'account_id', '3': 1, '4': 1, '5': 4, '10': 'accountId'},
+    {'1': 'email', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'email', '17': true},
+    {'1': 'password', '3': 3, '4': 1, '5': 9, '9': 1, '10': 'password', '17': true},
+  ],
+  '7': {},
+  '8': [
+    {'1': '_email'},
+    {'1': '_password'},
+  ],
+};
+
+/// Descriptor for `UpdateAccountRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List updateAccountRequestDescriptor = $convert.base64Decode(
+    'ChRVcGRhdGVBY2NvdW50UmVxdWVzdBIdCgphY2NvdW50X2lkGAEgASgEUglhY2NvdW50SWQSGQ'
+    'oFZW1haWwYAiABKAlIAFIFZW1haWyIAQESHwoIcGFzc3dvcmQYAyABKAlIAVIIcGFzc3dvcmSI'
+    'AQE6cZJBbgo2Kg5VcGRhdGUgQWNjb3VudDIRVXBkYXRlIGFuIEFjY291bnTSAQVlbWFpbNIBCH'
+    'Bhc3N3b3JkMjR7ImFjY291bnRfaWQiOiAiMSIsICJlbWFpbCI6ICJqb2huLmRvZUBleGFtcGxl'
+    'LmNvbSJ9QggKBl9lbWFpbEILCglfcGFzc3dvcmQ=');
+
+@$core.Deprecated('Use updateAccountResponseDescriptor instead')
+const UpdateAccountResponse$json = {
+  '1': 'UpdateAccountResponse',
+  '2': [
+    {'1': 'account', '3': 1, '4': 1, '5': 11, '6': '.pb.Account', '8': {}, '10': 'account'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `UpdateAccountResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List updateAccountResponseDescriptor = $convert.base64Decode(
+    'ChVVcGRhdGVBY2NvdW50UmVzcG9uc2USKgoHYWNjb3VudBgBIAEoCzILLnBiLkFjY291bnRCA5'
+    'JBAFIHYWNjb3VudDozkkEwCi4qD1VwZGF0ZWQgQWNjb3VudDIbUmV0dXJucyB0aGUgdXBkYXRl'
+    'ZCBBY2NvdW50');
+
diff --git a/frontend/app/lib/pb/rpc_update_account.pbserver.dart b/frontend/app/lib/pb/rpc_update_account.pbserver.dart
new file mode 100644
index 0000000..8268e1e
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_account.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_account.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_update_account.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_update_account_info.pb.dart b/frontend/app/lib/pb/rpc_update_account_info.pb.dart
new file mode 100644
index 0000000..f7066bf
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_account_info.pb.dart
@@ -0,0 +1,238 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'account_info.pb.dart' as $1;
+import 'google/protobuf/timestamp.pb.dart' as $0;
+
+class UpdateAccountInfoRequest extends $pb.GeneratedMessage {
+  factory UpdateAccountInfoRequest({
+    $fixnum.Int64? accountId,
+    $core.String? firstname,
+    $core.String? lastname,
+    $core.String? street,
+    $core.String? city,
+    $core.String? zip,
+    $core.String? country,
+    $core.String? phone,
+    $0.Timestamp? birthday,
+  }) {
+    final $result = create();
+    if (accountId != null) {
+      $result.accountId = accountId;
+    }
+    if (firstname != null) {
+      $result.firstname = firstname;
+    }
+    if (lastname != null) {
+      $result.lastname = lastname;
+    }
+    if (street != null) {
+      $result.street = street;
+    }
+    if (city != null) {
+      $result.city = city;
+    }
+    if (zip != null) {
+      $result.zip = zip;
+    }
+    if (country != null) {
+      $result.country = country;
+    }
+    if (phone != null) {
+      $result.phone = phone;
+    }
+    if (birthday != null) {
+      $result.birthday = birthday;
+    }
+    return $result;
+  }
+  UpdateAccountInfoRequest._() : super();
+  factory UpdateAccountInfoRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory UpdateAccountInfoRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UpdateAccountInfoRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'accountId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..aOS(4, _omitFieldNames ? '' : 'firstname')
+    ..aOS(5, _omitFieldNames ? '' : 'lastname')
+    ..aOS(6, _omitFieldNames ? '' : 'street')
+    ..aOS(7, _omitFieldNames ? '' : 'city')
+    ..aOS(8, _omitFieldNames ? '' : 'zip')
+    ..aOS(9, _omitFieldNames ? '' : 'country')
+    ..aOS(10, _omitFieldNames ? '' : 'phone')
+    ..aOM<$0.Timestamp>(11, _omitFieldNames ? '' : 'birthday', subBuilder: $0.Timestamp.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  UpdateAccountInfoRequest clone() => UpdateAccountInfoRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  UpdateAccountInfoRequest copyWith(void Function(UpdateAccountInfoRequest) updates) => super.copyWith((message) => updates(message as UpdateAccountInfoRequest)) as UpdateAccountInfoRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static UpdateAccountInfoRequest create() => UpdateAccountInfoRequest._();
+  UpdateAccountInfoRequest createEmptyInstance() => create();
+  static $pb.PbList<UpdateAccountInfoRequest> createRepeated() => $pb.PbList<UpdateAccountInfoRequest>();
+  @$core.pragma('dart2js:noInline')
+  static UpdateAccountInfoRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<UpdateAccountInfoRequest>(create);
+  static UpdateAccountInfoRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get accountId => $_getI64(0);
+  @$pb.TagNumber(1)
+  set accountId($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccountId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccountId() => clearField(1);
+
+  @$pb.TagNumber(4)
+  $core.String get firstname => $_getSZ(1);
+  @$pb.TagNumber(4)
+  set firstname($core.String v) { $_setString(1, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasFirstname() => $_has(1);
+  @$pb.TagNumber(4)
+  void clearFirstname() => clearField(4);
+
+  @$pb.TagNumber(5)
+  $core.String get lastname => $_getSZ(2);
+  @$pb.TagNumber(5)
+  set lastname($core.String v) { $_setString(2, v); }
+  @$pb.TagNumber(5)
+  $core.bool hasLastname() => $_has(2);
+  @$pb.TagNumber(5)
+  void clearLastname() => clearField(5);
+
+  @$pb.TagNumber(6)
+  $core.String get street => $_getSZ(3);
+  @$pb.TagNumber(6)
+  set street($core.String v) { $_setString(3, v); }
+  @$pb.TagNumber(6)
+  $core.bool hasStreet() => $_has(3);
+  @$pb.TagNumber(6)
+  void clearStreet() => clearField(6);
+
+  @$pb.TagNumber(7)
+  $core.String get city => $_getSZ(4);
+  @$pb.TagNumber(7)
+  set city($core.String v) { $_setString(4, v); }
+  @$pb.TagNumber(7)
+  $core.bool hasCity() => $_has(4);
+  @$pb.TagNumber(7)
+  void clearCity() => clearField(7);
+
+  @$pb.TagNumber(8)
+  $core.String get zip => $_getSZ(5);
+  @$pb.TagNumber(8)
+  set zip($core.String v) { $_setString(5, v); }
+  @$pb.TagNumber(8)
+  $core.bool hasZip() => $_has(5);
+  @$pb.TagNumber(8)
+  void clearZip() => clearField(8);
+
+  @$pb.TagNumber(9)
+  $core.String get country => $_getSZ(6);
+  @$pb.TagNumber(9)
+  set country($core.String v) { $_setString(6, v); }
+  @$pb.TagNumber(9)
+  $core.bool hasCountry() => $_has(6);
+  @$pb.TagNumber(9)
+  void clearCountry() => clearField(9);
+
+  @$pb.TagNumber(10)
+  $core.String get phone => $_getSZ(7);
+  @$pb.TagNumber(10)
+  set phone($core.String v) { $_setString(7, v); }
+  @$pb.TagNumber(10)
+  $core.bool hasPhone() => $_has(7);
+  @$pb.TagNumber(10)
+  void clearPhone() => clearField(10);
+
+  @$pb.TagNumber(11)
+  $0.Timestamp get birthday => $_getN(8);
+  @$pb.TagNumber(11)
+  set birthday($0.Timestamp v) { setField(11, v); }
+  @$pb.TagNumber(11)
+  $core.bool hasBirthday() => $_has(8);
+  @$pb.TagNumber(11)
+  void clearBirthday() => clearField(11);
+  @$pb.TagNumber(11)
+  $0.Timestamp ensureBirthday() => $_ensure(8);
+}
+
+class UpdateAccountInfoResponse extends $pb.GeneratedMessage {
+  factory UpdateAccountInfoResponse({
+    $1.AccountInfo? accountInfo,
+  }) {
+    final $result = create();
+    if (accountInfo != null) {
+      $result.accountInfo = accountInfo;
+    }
+    return $result;
+  }
+  UpdateAccountInfoResponse._() : super();
+  factory UpdateAccountInfoResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory UpdateAccountInfoResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UpdateAccountInfoResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOM<$1.AccountInfo>(1, _omitFieldNames ? '' : 'accountInfo', subBuilder: $1.AccountInfo.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  UpdateAccountInfoResponse clone() => UpdateAccountInfoResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  UpdateAccountInfoResponse copyWith(void Function(UpdateAccountInfoResponse) updates) => super.copyWith((message) => updates(message as UpdateAccountInfoResponse)) as UpdateAccountInfoResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static UpdateAccountInfoResponse create() => UpdateAccountInfoResponse._();
+  UpdateAccountInfoResponse createEmptyInstance() => create();
+  static $pb.PbList<UpdateAccountInfoResponse> createRepeated() => $pb.PbList<UpdateAccountInfoResponse>();
+  @$core.pragma('dart2js:noInline')
+  static UpdateAccountInfoResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<UpdateAccountInfoResponse>(create);
+  static UpdateAccountInfoResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $1.AccountInfo get accountInfo => $_getN(0);
+  @$pb.TagNumber(1)
+  set accountInfo($1.AccountInfo v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccountInfo() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccountInfo() => clearField(1);
+  @$pb.TagNumber(1)
+  $1.AccountInfo ensureAccountInfo() => $_ensure(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_update_account_info.pbenum.dart b/frontend/app/lib/pb/rpc_update_account_info.pbenum.dart
new file mode 100644
index 0000000..3522522
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_account_info.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_update_account_info.pbjson.dart b/frontend/app/lib/pb/rpc_update_account_info.pbjson.dart
new file mode 100644
index 0000000..284aca0
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_account_info.pbjson.dart
@@ -0,0 +1,70 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use updateAccountInfoRequestDescriptor instead')
+const UpdateAccountInfoRequest$json = {
+  '1': 'UpdateAccountInfoRequest',
+  '2': [
+    {'1': 'account_id', '3': 1, '4': 1, '5': 4, '10': 'accountId'},
+    {'1': 'firstname', '3': 4, '4': 1, '5': 9, '9': 0, '10': 'firstname', '17': true},
+    {'1': 'lastname', '3': 5, '4': 1, '5': 9, '9': 1, '10': 'lastname', '17': true},
+    {'1': 'street', '3': 6, '4': 1, '5': 9, '9': 2, '10': 'street', '17': true},
+    {'1': 'city', '3': 7, '4': 1, '5': 9, '9': 3, '10': 'city', '17': true},
+    {'1': 'zip', '3': 8, '4': 1, '5': 9, '9': 4, '10': 'zip', '17': true},
+    {'1': 'country', '3': 9, '4': 1, '5': 9, '9': 5, '10': 'country', '17': true},
+    {'1': 'phone', '3': 10, '4': 1, '5': 9, '9': 6, '10': 'phone', '17': true},
+    {'1': 'birthday', '3': 11, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '9': 7, '10': 'birthday', '17': true},
+  ],
+  '7': {},
+  '8': [
+    {'1': '_firstname'},
+    {'1': '_lastname'},
+    {'1': '_street'},
+    {'1': '_city'},
+    {'1': '_zip'},
+    {'1': '_country'},
+    {'1': '_phone'},
+    {'1': '_birthday'},
+  ],
+};
+
+/// Descriptor for `UpdateAccountInfoRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List updateAccountInfoRequestDescriptor = $convert.base64Decode(
+    'ChhVcGRhdGVBY2NvdW50SW5mb1JlcXVlc3QSHQoKYWNjb3VudF9pZBgBIAEoBFIJYWNjb3VudE'
+    'lkEiEKCWZpcnN0bmFtZRgEIAEoCUgAUglmaXJzdG5hbWWIAQESHwoIbGFzdG5hbWUYBSABKAlI'
+    'AVIIbGFzdG5hbWWIAQESGwoGc3RyZWV0GAYgASgJSAJSBnN0cmVldIgBARIXCgRjaXR5GAcgAS'
+    'gJSANSBGNpdHmIAQESFQoDemlwGAggASgJSARSA3ppcIgBARIdCgdjb3VudHJ5GAkgASgJSAVS'
+    'B2NvdW50cnmIAQESGQoFcGhvbmUYCiABKAlIBlIFcGhvbmWIAQESWAoIYmlydGhkYXkYCyABKA'
+    'syGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wQhuSQRhKFiIxOTkwLTEwLTA1VDAwOjAwOjAw'
+    'WiJIB1IIYmlydGhkYXmIAQE6ZJJBYQowKhJVcGRhdGUgQWNjb3VudEluZm8yFVVwZGF0ZSBhbi'
+    'BBY2NvdW50SW5mb9IBAmlkMi17ImFjY291bnRfaWQiOiAiMSIsICJzdHJlZXQiOiAiRGVhdGgg'
+    'U3RhciAyIn1CDAoKX2ZpcnN0bmFtZUILCglfbGFzdG5hbWVCCQoHX3N0cmVldEIHCgVfY2l0eU'
+    'IGCgRfemlwQgoKCF9jb3VudHJ5QggKBl9waG9uZUILCglfYmlydGhkYXk=');
+
+@$core.Deprecated('Use updateAccountInfoResponseDescriptor instead')
+const UpdateAccountInfoResponse$json = {
+  '1': 'UpdateAccountInfoResponse',
+  '2': [
+    {'1': 'account_info', '3': 1, '4': 1, '5': 11, '6': '.pb.AccountInfo', '8': {}, '10': 'accountInfo'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `UpdateAccountInfoResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List updateAccountInfoResponseDescriptor = $convert.base64Decode(
+    'ChlVcGRhdGVBY2NvdW50SW5mb1Jlc3BvbnNlEjcKDGFjY291bnRfaW5mbxgBIAEoCzIPLnBiLk'
+    'FjY291bnRJbmZvQgOSQQBSC2FjY291bnRJbmZvOjOSQTAKLioPVXBkYXRlZCBBY2NvdW50MhtS'
+    'ZXR1cm5zIHRoZSB1cGRhdGVkIEFjY291bnQ=');
+
diff --git a/frontend/app/lib/pb/rpc_update_account_info.pbserver.dart b/frontend/app/lib/pb/rpc_update_account_info.pbserver.dart
new file mode 100644
index 0000000..181645c
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_account_info.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_account_info.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_update_account_info.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_update_account_privacy.pb.dart b/frontend/app/lib/pb/rpc_update_account_privacy.pb.dart
new file mode 100644
index 0000000..68719c9
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_account_privacy.pb.dart
@@ -0,0 +1,137 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_account_privacy.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'account_info.pb.dart' as $1;
+
+class UpdateAccountPrivacyRequest extends $pb.GeneratedMessage {
+  factory UpdateAccountPrivacyRequest({
+    $fixnum.Int64? accountId,
+    $core.bool? privacyAccepted,
+  }) {
+    final $result = create();
+    if (accountId != null) {
+      $result.accountId = accountId;
+    }
+    if (privacyAccepted != null) {
+      $result.privacyAccepted = privacyAccepted;
+    }
+    return $result;
+  }
+  UpdateAccountPrivacyRequest._() : super();
+  factory UpdateAccountPrivacyRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory UpdateAccountPrivacyRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UpdateAccountPrivacyRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'accountId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..aOB(2, _omitFieldNames ? '' : 'privacyAccepted')
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  UpdateAccountPrivacyRequest clone() => UpdateAccountPrivacyRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  UpdateAccountPrivacyRequest copyWith(void Function(UpdateAccountPrivacyRequest) updates) => super.copyWith((message) => updates(message as UpdateAccountPrivacyRequest)) as UpdateAccountPrivacyRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static UpdateAccountPrivacyRequest create() => UpdateAccountPrivacyRequest._();
+  UpdateAccountPrivacyRequest createEmptyInstance() => create();
+  static $pb.PbList<UpdateAccountPrivacyRequest> createRepeated() => $pb.PbList<UpdateAccountPrivacyRequest>();
+  @$core.pragma('dart2js:noInline')
+  static UpdateAccountPrivacyRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<UpdateAccountPrivacyRequest>(create);
+  static UpdateAccountPrivacyRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get accountId => $_getI64(0);
+  @$pb.TagNumber(1)
+  set accountId($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccountId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccountId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.bool get privacyAccepted => $_getBF(1);
+  @$pb.TagNumber(2)
+  set privacyAccepted($core.bool v) { $_setBool(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasPrivacyAccepted() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearPrivacyAccepted() => clearField(2);
+}
+
+class UpdateAccountPrivacyResponse extends $pb.GeneratedMessage {
+  factory UpdateAccountPrivacyResponse({
+    $1.AccountInfo? accountInfo,
+  }) {
+    final $result = create();
+    if (accountInfo != null) {
+      $result.accountInfo = accountInfo;
+    }
+    return $result;
+  }
+  UpdateAccountPrivacyResponse._() : super();
+  factory UpdateAccountPrivacyResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory UpdateAccountPrivacyResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UpdateAccountPrivacyResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOM<$1.AccountInfo>(1, _omitFieldNames ? '' : 'accountInfo', subBuilder: $1.AccountInfo.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  UpdateAccountPrivacyResponse clone() => UpdateAccountPrivacyResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  UpdateAccountPrivacyResponse copyWith(void Function(UpdateAccountPrivacyResponse) updates) => super.copyWith((message) => updates(message as UpdateAccountPrivacyResponse)) as UpdateAccountPrivacyResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static UpdateAccountPrivacyResponse create() => UpdateAccountPrivacyResponse._();
+  UpdateAccountPrivacyResponse createEmptyInstance() => create();
+  static $pb.PbList<UpdateAccountPrivacyResponse> createRepeated() => $pb.PbList<UpdateAccountPrivacyResponse>();
+  @$core.pragma('dart2js:noInline')
+  static UpdateAccountPrivacyResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<UpdateAccountPrivacyResponse>(create);
+  static UpdateAccountPrivacyResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $1.AccountInfo get accountInfo => $_getN(0);
+  @$pb.TagNumber(1)
+  set accountInfo($1.AccountInfo v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccountInfo() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccountInfo() => clearField(1);
+  @$pb.TagNumber(1)
+  $1.AccountInfo ensureAccountInfo() => $_ensure(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_update_account_privacy.pbenum.dart b/frontend/app/lib/pb/rpc_update_account_privacy.pbenum.dart
new file mode 100644
index 0000000..1e47f94
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_account_privacy.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_account_privacy.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_update_account_privacy.pbjson.dart b/frontend/app/lib/pb/rpc_update_account_privacy.pbjson.dart
new file mode 100644
index 0000000..55d4116
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_account_privacy.pbjson.dart
@@ -0,0 +1,49 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_account_privacy.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use updateAccountPrivacyRequestDescriptor instead')
+const UpdateAccountPrivacyRequest$json = {
+  '1': 'UpdateAccountPrivacyRequest',
+  '2': [
+    {'1': 'account_id', '3': 1, '4': 1, '5': 4, '8': {}, '10': 'accountId'},
+    {'1': 'privacy_accepted', '3': 2, '4': 1, '5': 8, '8': {}, '10': 'privacyAccepted'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `UpdateAccountPrivacyRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List updateAccountPrivacyRequestDescriptor = $convert.base64Decode(
+    'ChtVcGRhdGVBY2NvdW50UHJpdmFjeVJlcXVlc3QSLQoKYWNjb3VudF9pZBgBIAEoBEIOkkELSg'
+    'ExogIFaW50NjRSCWFjY291bnRJZBI1ChBwcml2YWN5X2FjY2VwdGVkGAIgASgIQgqSQQdKBWZh'
+    'bHNlUg9wcml2YWN5QWNjZXB0ZWQ6oQGSQZ0BCmsqI1VwZGF0ZSBBY2NvdW50IEluZm8gUHJpdm'
+    'FjeSBDb25zZW50MixVcGRhdGUgdGhlIFByaXZhY3kgQ29uc2VudCBvZiBhbiBBY2NvdW50SW5m'
+    'b9IBAmlk0gEQcHJpdmFjeV9hY2NlcHRlZDIueyJhY2NvdW50X2lkIjogIjEiLCAicHJpdmFjeV'
+    '9hY2NlcHRlZCI6IHRydWUgfQ==');
+
+@$core.Deprecated('Use updateAccountPrivacyResponseDescriptor instead')
+const UpdateAccountPrivacyResponse$json = {
+  '1': 'UpdateAccountPrivacyResponse',
+  '2': [
+    {'1': 'account_info', '3': 1, '4': 1, '5': 11, '6': '.pb.AccountInfo', '8': {}, '10': 'accountInfo'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `UpdateAccountPrivacyResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List updateAccountPrivacyResponseDescriptor = $convert.base64Decode(
+    'ChxVcGRhdGVBY2NvdW50UHJpdmFjeVJlc3BvbnNlEkwKDGFjY291bnRfaW5mbxgBIAEoCzIPLn'
+    'BiLkFjY291bnRJbmZvQhiSQRUqE1VwZGF0ZWQgQWNjb3VudEluZm9SC2FjY291bnRJbmZvOiuS'
+    'QSgKJiokVXBkYXRlIEFjY291bnQgSW5mbyBQcml2YWN5IFJlc3BvbnNl');
+
diff --git a/frontend/app/lib/pb/rpc_update_account_privacy.pbserver.dart b/frontend/app/lib/pb/rpc_update_account_privacy.pbserver.dart
new file mode 100644
index 0000000..2b7d3b6
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_account_privacy.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_account_privacy.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_update_account_privacy.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_update_payment.pb.dart b/frontend/app/lib/pb/rpc_update_payment.pb.dart
new file mode 100644
index 0000000..42a8739
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_payment.pb.dart
@@ -0,0 +1,235 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'payment.pb.dart' as $3;
+
+class UpdatePaymentRequest extends $pb.GeneratedMessage {
+  factory UpdatePaymentRequest({
+    $fixnum.Int64? id,
+    $core.String? paymentCategory,
+    $core.String? bankname,
+    $core.String? iBAN,
+    $core.String? bIC,
+    $core.String? paypalAccount,
+    $core.String? paypalId,
+    $core.String? paymentSystem,
+    $core.String? type,
+  }) {
+    final $result = create();
+    if (id != null) {
+      $result.id = id;
+    }
+    if (paymentCategory != null) {
+      $result.paymentCategory = paymentCategory;
+    }
+    if (bankname != null) {
+      $result.bankname = bankname;
+    }
+    if (iBAN != null) {
+      $result.iBAN = iBAN;
+    }
+    if (bIC != null) {
+      $result.bIC = bIC;
+    }
+    if (paypalAccount != null) {
+      $result.paypalAccount = paypalAccount;
+    }
+    if (paypalId != null) {
+      $result.paypalId = paypalId;
+    }
+    if (paymentSystem != null) {
+      $result.paymentSystem = paymentSystem;
+    }
+    if (type != null) {
+      $result.type = type;
+    }
+    return $result;
+  }
+  UpdatePaymentRequest._() : super();
+  factory UpdatePaymentRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory UpdatePaymentRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UpdatePaymentRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..aOS(2, _omitFieldNames ? '' : 'paymentCategory')
+    ..aOS(3, _omitFieldNames ? '' : 'bankname')
+    ..aOS(4, _omitFieldNames ? '' : 'IBAN', protoName: 'IBAN')
+    ..aOS(5, _omitFieldNames ? '' : 'BIC', protoName: 'BIC')
+    ..aOS(6, _omitFieldNames ? '' : 'paypalAccount')
+    ..aOS(7, _omitFieldNames ? '' : 'paypalId')
+    ..aOS(8, _omitFieldNames ? '' : 'paymentSystem')
+    ..aOS(9, _omitFieldNames ? '' : 'type')
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  UpdatePaymentRequest clone() => UpdatePaymentRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  UpdatePaymentRequest copyWith(void Function(UpdatePaymentRequest) updates) => super.copyWith((message) => updates(message as UpdatePaymentRequest)) as UpdatePaymentRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static UpdatePaymentRequest create() => UpdatePaymentRequest._();
+  UpdatePaymentRequest createEmptyInstance() => create();
+  static $pb.PbList<UpdatePaymentRequest> createRepeated() => $pb.PbList<UpdatePaymentRequest>();
+  @$core.pragma('dart2js:noInline')
+  static UpdatePaymentRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<UpdatePaymentRequest>(create);
+  static UpdatePaymentRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get id => $_getI64(0);
+  @$pb.TagNumber(1)
+  set id($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.String get paymentCategory => $_getSZ(1);
+  @$pb.TagNumber(2)
+  set paymentCategory($core.String v) { $_setString(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasPaymentCategory() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearPaymentCategory() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $core.String get bankname => $_getSZ(2);
+  @$pb.TagNumber(3)
+  set bankname($core.String v) { $_setString(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasBankname() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearBankname() => clearField(3);
+
+  @$pb.TagNumber(4)
+  $core.String get iBAN => $_getSZ(3);
+  @$pb.TagNumber(4)
+  set iBAN($core.String v) { $_setString(3, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasIBAN() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearIBAN() => clearField(4);
+
+  @$pb.TagNumber(5)
+  $core.String get bIC => $_getSZ(4);
+  @$pb.TagNumber(5)
+  set bIC($core.String v) { $_setString(4, v); }
+  @$pb.TagNumber(5)
+  $core.bool hasBIC() => $_has(4);
+  @$pb.TagNumber(5)
+  void clearBIC() => clearField(5);
+
+  @$pb.TagNumber(6)
+  $core.String get paypalAccount => $_getSZ(5);
+  @$pb.TagNumber(6)
+  set paypalAccount($core.String v) { $_setString(5, v); }
+  @$pb.TagNumber(6)
+  $core.bool hasPaypalAccount() => $_has(5);
+  @$pb.TagNumber(6)
+  void clearPaypalAccount() => clearField(6);
+
+  @$pb.TagNumber(7)
+  $core.String get paypalId => $_getSZ(6);
+  @$pb.TagNumber(7)
+  set paypalId($core.String v) { $_setString(6, v); }
+  @$pb.TagNumber(7)
+  $core.bool hasPaypalId() => $_has(6);
+  @$pb.TagNumber(7)
+  void clearPaypalId() => clearField(7);
+
+  @$pb.TagNumber(8)
+  $core.String get paymentSystem => $_getSZ(7);
+  @$pb.TagNumber(8)
+  set paymentSystem($core.String v) { $_setString(7, v); }
+  @$pb.TagNumber(8)
+  $core.bool hasPaymentSystem() => $_has(7);
+  @$pb.TagNumber(8)
+  void clearPaymentSystem() => clearField(8);
+
+  @$pb.TagNumber(9)
+  $core.String get type => $_getSZ(8);
+  @$pb.TagNumber(9)
+  set type($core.String v) { $_setString(8, v); }
+  @$pb.TagNumber(9)
+  $core.bool hasType() => $_has(8);
+  @$pb.TagNumber(9)
+  void clearType() => clearField(9);
+}
+
+class UpdatePaymentResponse extends $pb.GeneratedMessage {
+  factory UpdatePaymentResponse({
+    $3.Payment? payment,
+  }) {
+    final $result = create();
+    if (payment != null) {
+      $result.payment = payment;
+    }
+    return $result;
+  }
+  UpdatePaymentResponse._() : super();
+  factory UpdatePaymentResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory UpdatePaymentResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UpdatePaymentResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOM<$3.Payment>(1, _omitFieldNames ? '' : 'payment', subBuilder: $3.Payment.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  UpdatePaymentResponse clone() => UpdatePaymentResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  UpdatePaymentResponse copyWith(void Function(UpdatePaymentResponse) updates) => super.copyWith((message) => updates(message as UpdatePaymentResponse)) as UpdatePaymentResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static UpdatePaymentResponse create() => UpdatePaymentResponse._();
+  UpdatePaymentResponse createEmptyInstance() => create();
+  static $pb.PbList<UpdatePaymentResponse> createRepeated() => $pb.PbList<UpdatePaymentResponse>();
+  @$core.pragma('dart2js:noInline')
+  static UpdatePaymentResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<UpdatePaymentResponse>(create);
+  static UpdatePaymentResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $3.Payment get payment => $_getN(0);
+  @$pb.TagNumber(1)
+  set payment($3.Payment v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasPayment() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearPayment() => clearField(1);
+  @$pb.TagNumber(1)
+  $3.Payment ensurePayment() => $_ensure(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_update_payment.pbenum.dart b/frontend/app/lib/pb/rpc_update_payment.pbenum.dart
new file mode 100644
index 0000000..450d71c
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_payment.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_update_payment.pbjson.dart b/frontend/app/lib/pb/rpc_update_payment.pbjson.dart
new file mode 100644
index 0000000..ae8f9ad
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_payment.pbjson.dart
@@ -0,0 +1,73 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use updatePaymentRequestDescriptor instead')
+const UpdatePaymentRequest$json = {
+  '1': 'UpdatePaymentRequest',
+  '2': [
+    {'1': 'id', '3': 1, '4': 1, '5': 4, '10': 'id'},
+    {'1': 'payment_category', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'paymentCategory', '17': true},
+    {'1': 'bankname', '3': 3, '4': 1, '5': 9, '9': 1, '10': 'bankname', '17': true},
+    {'1': 'IBAN', '3': 4, '4': 1, '5': 9, '9': 2, '10': 'IBAN', '17': true},
+    {'1': 'BIC', '3': 5, '4': 1, '5': 9, '9': 3, '10': 'BIC', '17': true},
+    {'1': 'paypal_account', '3': 6, '4': 1, '5': 9, '9': 4, '10': 'paypalAccount', '17': true},
+    {'1': 'paypal_id', '3': 7, '4': 1, '5': 9, '9': 5, '10': 'paypalId', '17': true},
+    {'1': 'payment_system', '3': 8, '4': 1, '5': 9, '9': 6, '10': 'paymentSystem', '17': true},
+    {'1': 'type', '3': 9, '4': 1, '5': 9, '9': 7, '10': 'type', '17': true},
+  ],
+  '7': {},
+  '8': [
+    {'1': '_payment_category'},
+    {'1': '_bankname'},
+    {'1': '_IBAN'},
+    {'1': '_BIC'},
+    {'1': '_paypal_account'},
+    {'1': '_paypal_id'},
+    {'1': '_payment_system'},
+    {'1': '_type'},
+  ],
+};
+
+/// Descriptor for `UpdatePaymentRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List updatePaymentRequestDescriptor = $convert.base64Decode(
+    'ChRVcGRhdGVQYXltZW50UmVxdWVzdBIOCgJpZBgBIAEoBFICaWQSLgoQcGF5bWVudF9jYXRlZ2'
+    '9yeRgCIAEoCUgAUg9wYXltZW50Q2F0ZWdvcnmIAQESHwoIYmFua25hbWUYAyABKAlIAVIIYmFu'
+    'a25hbWWIAQESFwoESUJBThgEIAEoCUgCUgRJQkFOiAEBEhUKA0JJQxgFIAEoCUgDUgNCSUOIAQ'
+    'ESKgoOcGF5cGFsX2FjY291bnQYBiABKAlIBFINcGF5cGFsQWNjb3VudIgBARIgCglwYXlwYWxf'
+    'aWQYByABKAlIBVIIcGF5cGFsSWSIAQESKgoOcGF5bWVudF9zeXN0ZW0YCCABKAlIBlINcGF5bW'
+    'VudFN5c3RlbYgBARIXCgR0eXBlGAkgASgJSAdSBHR5cGWIAQE67wGSQesBCigqDlVwZGF0ZSBQ'
+    'YXltZW50MhFVcGRhdGUgYW4gUGF5bWVudNIBAmlkMr4BeyJpZCI6ICIxIiwgInBheW1lbnRfY2'
+    'F0ZWdvcnkiOiAiVEJEOiBwYXlwYWwiLCAicGF5cGFsX2FjY291bnQiOiAiam9obi5kb2VAZXhh'
+    'bXBsZS5jb20iLCAicGF5cGFsX2lkIjogInRoaXMtaXMtYS1wYXlwYWwtaWQiLCAicGF5bWVudF'
+    '9zeXN0ZW0iOiAiVEJEOiBwYXlwYWwgc3lzdGVtIiwgInR5cGUiOiAiVEJEOiBzb21lIHR5cGUi'
+    'fUITChFfcGF5bWVudF9jYXRlZ29yeUILCglfYmFua25hbWVCBwoFX0lCQU5CBgoEX0JJQ0IRCg'
+    '9fcGF5cGFsX2FjY291bnRCDAoKX3BheXBhbF9pZEIRCg9fcGF5bWVudF9zeXN0ZW1CBwoFX3R5'
+    'cGU=');
+
+@$core.Deprecated('Use updatePaymentResponseDescriptor instead')
+const UpdatePaymentResponse$json = {
+  '1': 'UpdatePaymentResponse',
+  '2': [
+    {'1': 'payment', '3': 1, '4': 1, '5': 11, '6': '.pb.Payment', '8': {}, '10': 'payment'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `UpdatePaymentResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List updatePaymentResponseDescriptor = $convert.base64Decode(
+    'ChVVcGRhdGVQYXltZW50UmVzcG9uc2USKgoHcGF5bWVudBgBIAEoCzILLnBiLlBheW1lbnRCA5'
+    'JBAFIHcGF5bWVudDozkkEwCi4qD1VwZGF0ZWQgUGF5bWVudDIbUmV0dXJucyB0aGUgdXBkYXRl'
+    'ZCBQYXltZW50');
+
diff --git a/frontend/app/lib/pb/rpc_update_payment.pbserver.dart b/frontend/app/lib/pb/rpc_update_payment.pbserver.dart
new file mode 100644
index 0000000..b3179bb
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_payment.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_payment.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_update_payment.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_update_person.pb.dart b/frontend/app/lib/pb/rpc_update_person.pb.dart
new file mode 100644
index 0000000..d904eba
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_person.pb.dart
@@ -0,0 +1,224 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'google/protobuf/timestamp.pb.dart' as $0;
+import 'person.pb.dart' as $4;
+
+class UpdatePersonRequest extends $pb.GeneratedMessage {
+  factory UpdatePersonRequest({
+    $fixnum.Int64? id,
+    $core.String? firstname,
+    $core.String? lastname,
+    $core.String? street,
+    $core.String? city,
+    $core.String? zip,
+    $core.String? country,
+    $0.Timestamp? birthday,
+  }) {
+    final $result = create();
+    if (id != null) {
+      $result.id = id;
+    }
+    if (firstname != null) {
+      $result.firstname = firstname;
+    }
+    if (lastname != null) {
+      $result.lastname = lastname;
+    }
+    if (street != null) {
+      $result.street = street;
+    }
+    if (city != null) {
+      $result.city = city;
+    }
+    if (zip != null) {
+      $result.zip = zip;
+    }
+    if (country != null) {
+      $result.country = country;
+    }
+    if (birthday != null) {
+      $result.birthday = birthday;
+    }
+    return $result;
+  }
+  UpdatePersonRequest._() : super();
+  factory UpdatePersonRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory UpdatePersonRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UpdatePersonRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..aOS(2, _omitFieldNames ? '' : 'firstname')
+    ..aOS(3, _omitFieldNames ? '' : 'lastname')
+    ..aOS(4, _omitFieldNames ? '' : 'street')
+    ..aOS(5, _omitFieldNames ? '' : 'city')
+    ..aOS(6, _omitFieldNames ? '' : 'zip')
+    ..aOS(7, _omitFieldNames ? '' : 'country')
+    ..aOM<$0.Timestamp>(8, _omitFieldNames ? '' : 'birthday', subBuilder: $0.Timestamp.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  UpdatePersonRequest clone() => UpdatePersonRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  UpdatePersonRequest copyWith(void Function(UpdatePersonRequest) updates) => super.copyWith((message) => updates(message as UpdatePersonRequest)) as UpdatePersonRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static UpdatePersonRequest create() => UpdatePersonRequest._();
+  UpdatePersonRequest createEmptyInstance() => create();
+  static $pb.PbList<UpdatePersonRequest> createRepeated() => $pb.PbList<UpdatePersonRequest>();
+  @$core.pragma('dart2js:noInline')
+  static UpdatePersonRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<UpdatePersonRequest>(create);
+  static UpdatePersonRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get id => $_getI64(0);
+  @$pb.TagNumber(1)
+  set id($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.String get firstname => $_getSZ(1);
+  @$pb.TagNumber(2)
+  set firstname($core.String v) { $_setString(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasFirstname() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearFirstname() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $core.String get lastname => $_getSZ(2);
+  @$pb.TagNumber(3)
+  set lastname($core.String v) { $_setString(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasLastname() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearLastname() => clearField(3);
+
+  @$pb.TagNumber(4)
+  $core.String get street => $_getSZ(3);
+  @$pb.TagNumber(4)
+  set street($core.String v) { $_setString(3, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasStreet() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearStreet() => clearField(4);
+
+  @$pb.TagNumber(5)
+  $core.String get city => $_getSZ(4);
+  @$pb.TagNumber(5)
+  set city($core.String v) { $_setString(4, v); }
+  @$pb.TagNumber(5)
+  $core.bool hasCity() => $_has(4);
+  @$pb.TagNumber(5)
+  void clearCity() => clearField(5);
+
+  @$pb.TagNumber(6)
+  $core.String get zip => $_getSZ(5);
+  @$pb.TagNumber(6)
+  set zip($core.String v) { $_setString(5, v); }
+  @$pb.TagNumber(6)
+  $core.bool hasZip() => $_has(5);
+  @$pb.TagNumber(6)
+  void clearZip() => clearField(6);
+
+  @$pb.TagNumber(7)
+  $core.String get country => $_getSZ(6);
+  @$pb.TagNumber(7)
+  set country($core.String v) { $_setString(6, v); }
+  @$pb.TagNumber(7)
+  $core.bool hasCountry() => $_has(6);
+  @$pb.TagNumber(7)
+  void clearCountry() => clearField(7);
+
+  @$pb.TagNumber(8)
+  $0.Timestamp get birthday => $_getN(7);
+  @$pb.TagNumber(8)
+  set birthday($0.Timestamp v) { setField(8, v); }
+  @$pb.TagNumber(8)
+  $core.bool hasBirthday() => $_has(7);
+  @$pb.TagNumber(8)
+  void clearBirthday() => clearField(8);
+  @$pb.TagNumber(8)
+  $0.Timestamp ensureBirthday() => $_ensure(7);
+}
+
+class UpdatePersonResponse extends $pb.GeneratedMessage {
+  factory UpdatePersonResponse({
+    $4.Person? person,
+  }) {
+    final $result = create();
+    if (person != null) {
+      $result.person = person;
+    }
+    return $result;
+  }
+  UpdatePersonResponse._() : super();
+  factory UpdatePersonResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory UpdatePersonResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UpdatePersonResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOM<$4.Person>(1, _omitFieldNames ? '' : 'person', subBuilder: $4.Person.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  UpdatePersonResponse clone() => UpdatePersonResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  UpdatePersonResponse copyWith(void Function(UpdatePersonResponse) updates) => super.copyWith((message) => updates(message as UpdatePersonResponse)) as UpdatePersonResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static UpdatePersonResponse create() => UpdatePersonResponse._();
+  UpdatePersonResponse createEmptyInstance() => create();
+  static $pb.PbList<UpdatePersonResponse> createRepeated() => $pb.PbList<UpdatePersonResponse>();
+  @$core.pragma('dart2js:noInline')
+  static UpdatePersonResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<UpdatePersonResponse>(create);
+  static UpdatePersonResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $4.Person get person => $_getN(0);
+  @$pb.TagNumber(1)
+  set person($4.Person v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasPerson() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearPerson() => clearField(1);
+  @$pb.TagNumber(1)
+  $4.Person ensurePerson() => $_ensure(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_update_person.pbenum.dart b/frontend/app/lib/pb/rpc_update_person.pbenum.dart
new file mode 100644
index 0000000..50c3824
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_person.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_update_person.pbjson.dart b/frontend/app/lib/pb/rpc_update_person.pbjson.dart
new file mode 100644
index 0000000..5df2656
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_person.pbjson.dart
@@ -0,0 +1,70 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use updatePersonRequestDescriptor instead')
+const UpdatePersonRequest$json = {
+  '1': 'UpdatePersonRequest',
+  '2': [
+    {'1': 'id', '3': 1, '4': 1, '5': 4, '10': 'id'},
+    {'1': 'firstname', '3': 2, '4': 1, '5': 9, '9': 0, '10': 'firstname', '17': true},
+    {'1': 'lastname', '3': 3, '4': 1, '5': 9, '9': 1, '10': 'lastname', '17': true},
+    {'1': 'street', '3': 4, '4': 1, '5': 9, '9': 2, '10': 'street', '17': true},
+    {'1': 'city', '3': 5, '4': 1, '5': 9, '9': 3, '10': 'city', '17': true},
+    {'1': 'zip', '3': 6, '4': 1, '5': 9, '9': 4, '10': 'zip', '17': true},
+    {'1': 'country', '3': 7, '4': 1, '5': 9, '9': 5, '10': 'country', '17': true},
+    {'1': 'birthday', '3': 8, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '9': 6, '10': 'birthday', '17': true},
+  ],
+  '7': {},
+  '8': [
+    {'1': '_firstname'},
+    {'1': '_lastname'},
+    {'1': '_street'},
+    {'1': '_city'},
+    {'1': '_zip'},
+    {'1': '_country'},
+    {'1': '_birthday'},
+  ],
+};
+
+/// Descriptor for `UpdatePersonRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List updatePersonRequestDescriptor = $convert.base64Decode(
+    'ChNVcGRhdGVQZXJzb25SZXF1ZXN0Eg4KAmlkGAEgASgEUgJpZBIhCglmaXJzdG5hbWUYAiABKA'
+    'lIAFIJZmlyc3RuYW1liAEBEh8KCGxhc3RuYW1lGAMgASgJSAFSCGxhc3RuYW1liAEBEhsKBnN0'
+    'cmVldBgEIAEoCUgCUgZzdHJlZXSIAQESFwoEY2l0eRgFIAEoCUgDUgRjaXR5iAEBEhUKA3ppcB'
+    'gGIAEoCUgEUgN6aXCIAQESHQoHY291bnRyeRgHIAEoCUgFUgdjb3VudHJ5iAEBElgKCGJpcnRo'
+    'ZGF5GAggASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcEIbkkEYShYiMTk5MC0xMC0wNV'
+    'QwMDowMDowMFoiSAZSCGJpcnRoZGF5iAEBOuUBkkHhAQomKg1VcGRhdGUgUGVyc29uMhBVcGRh'
+    'dGUgYW4gUGVyc29u0gECaWQytgF7ImlkIjogIjEiLCAiZmlyc3RuYW1lIjogIkpvaG4iLCAibG'
+    'FzdG5hbWUiOiAiRG9lIiwgInBob25lIjogIiIsICJzdHJlZXQiOiAiRGVhdGggU3RhciAzIiwg'
+    'InppcCI6ICIwODE2IiwgImNpdHkiOiAiTW9udGFuYSIsICJjb3VudHJ5IjogIkNhbmFkYSIsIC'
+    'JiaXJ0aGRheSI6ICIxOTkyLTEwLTA1VDAwOjAwOjAwWiIgfUIMCgpfZmlyc3RuYW1lQgsKCV9s'
+    'YXN0bmFtZUIJCgdfc3RyZWV0QgcKBV9jaXR5QgYKBF96aXBCCgoIX2NvdW50cnlCCwoJX2Jpcn'
+    'RoZGF5');
+
+@$core.Deprecated('Use updatePersonResponseDescriptor instead')
+const UpdatePersonResponse$json = {
+  '1': 'UpdatePersonResponse',
+  '2': [
+    {'1': 'person', '3': 1, '4': 1, '5': 11, '6': '.pb.Person', '8': {}, '10': 'person'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `UpdatePersonResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List updatePersonResponseDescriptor = $convert.base64Decode(
+    'ChRVcGRhdGVQZXJzb25SZXNwb25zZRInCgZwZXJzb24YASABKAsyCi5wYi5QZXJzb25CA5JBAF'
+    'IGcGVyc29uOjGSQS4KLCoOVXBkYXRlZCBQZXJzb24yGlJldHVybnMgdGhlIHVwZGF0ZWQgUGVy'
+    'c29u');
+
diff --git a/frontend/app/lib/pb/rpc_update_person.pbserver.dart b/frontend/app/lib/pb/rpc_update_person.pbserver.dart
new file mode 100644
index 0000000..784dbe1
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_update_person.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_update_person.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_update_person.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_upload_document.pb.dart b/frontend/app/lib/pb/rpc_upload_document.pb.dart
new file mode 100644
index 0000000..d3cec63
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_upload_document.pb.dart
@@ -0,0 +1,151 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_upload_document.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'document.pb.dart' as $7;
+
+class UploadDocumentRequest extends $pb.GeneratedMessage {
+  factory UploadDocumentRequest({
+    $core.List<$core.int>? file,
+    $fixnum.Int64? personId,
+    $fixnum.Int64? mailId,
+  }) {
+    final $result = create();
+    if (file != null) {
+      $result.file = file;
+    }
+    if (personId != null) {
+      $result.personId = personId;
+    }
+    if (mailId != null) {
+      $result.mailId = mailId;
+    }
+    return $result;
+  }
+  UploadDocumentRequest._() : super();
+  factory UploadDocumentRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory UploadDocumentRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UploadDocumentRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$core.List<$core.int>>(1, _omitFieldNames ? '' : 'file', $pb.PbFieldType.OY)
+    ..a<$fixnum.Int64>(2, _omitFieldNames ? '' : 'personId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'mailId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  UploadDocumentRequest clone() => UploadDocumentRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  UploadDocumentRequest copyWith(void Function(UploadDocumentRequest) updates) => super.copyWith((message) => updates(message as UploadDocumentRequest)) as UploadDocumentRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static UploadDocumentRequest create() => UploadDocumentRequest._();
+  UploadDocumentRequest createEmptyInstance() => create();
+  static $pb.PbList<UploadDocumentRequest> createRepeated() => $pb.PbList<UploadDocumentRequest>();
+  @$core.pragma('dart2js:noInline')
+  static UploadDocumentRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<UploadDocumentRequest>(create);
+  static UploadDocumentRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.List<$core.int> get file => $_getN(0);
+  @$pb.TagNumber(1)
+  set file($core.List<$core.int> v) { $_setBytes(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasFile() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearFile() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $fixnum.Int64 get personId => $_getI64(1);
+  @$pb.TagNumber(2)
+  set personId($fixnum.Int64 v) { $_setInt64(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasPersonId() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearPersonId() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $fixnum.Int64 get mailId => $_getI64(2);
+  @$pb.TagNumber(3)
+  set mailId($fixnum.Int64 v) { $_setInt64(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasMailId() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearMailId() => clearField(3);
+}
+
+class UploadDocumentResponse extends $pb.GeneratedMessage {
+  factory UploadDocumentResponse({
+    $7.Document? document,
+  }) {
+    final $result = create();
+    if (document != null) {
+      $result.document = document;
+    }
+    return $result;
+  }
+  UploadDocumentResponse._() : super();
+  factory UploadDocumentResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory UploadDocumentResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UploadDocumentResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOM<$7.Document>(1, _omitFieldNames ? '' : 'document', subBuilder: $7.Document.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  UploadDocumentResponse clone() => UploadDocumentResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  UploadDocumentResponse copyWith(void Function(UploadDocumentResponse) updates) => super.copyWith((message) => updates(message as UploadDocumentResponse)) as UploadDocumentResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static UploadDocumentResponse create() => UploadDocumentResponse._();
+  UploadDocumentResponse createEmptyInstance() => create();
+  static $pb.PbList<UploadDocumentResponse> createRepeated() => $pb.PbList<UploadDocumentResponse>();
+  @$core.pragma('dart2js:noInline')
+  static UploadDocumentResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<UploadDocumentResponse>(create);
+  static UploadDocumentResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $7.Document get document => $_getN(0);
+  @$pb.TagNumber(1)
+  set document($7.Document v) { setField(1, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasDocument() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearDocument() => clearField(1);
+  @$pb.TagNumber(1)
+  $7.Document ensureDocument() => $_ensure(0);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_upload_document.pbenum.dart b/frontend/app/lib/pb/rpc_upload_document.pbenum.dart
new file mode 100644
index 0000000..556406f
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_upload_document.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_upload_document.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_upload_document.pbjson.dart b/frontend/app/lib/pb/rpc_upload_document.pbjson.dart
new file mode 100644
index 0000000..d5c90fa
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_upload_document.pbjson.dart
@@ -0,0 +1,52 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_upload_document.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use uploadDocumentRequestDescriptor instead')
+const UploadDocumentRequest$json = {
+  '1': 'UploadDocumentRequest',
+  '2': [
+    {'1': 'file', '3': 1, '4': 1, '5': 12, '10': 'file'},
+    {'1': 'person_id', '3': 2, '4': 1, '5': 4, '9': 0, '10': 'personId', '17': true},
+    {'1': 'mail_id', '3': 3, '4': 1, '5': 4, '9': 1, '10': 'mailId', '17': true},
+  ],
+  '7': {},
+  '8': [
+    {'1': '_person_id'},
+    {'1': '_mail_id'},
+  ],
+};
+
+/// Descriptor for `UploadDocumentRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List uploadDocumentRequestDescriptor = $convert.base64Decode(
+    'ChVVcGxvYWREb2N1bWVudFJlcXVlc3QSEgoEZmlsZRgBIAEoDFIEZmlsZRIgCglwZXJzb25faW'
+    'QYAiABKARIAFIIcGVyc29uSWSIAQESHAoHbWFpbF9pZBgDIAEoBEgBUgZtYWlsSWSIAQE6XJJB'
+    'WQpCKhpVcGxvYWREb2N1bWVudCBbb25seSBIVFRQXTIdVXBsb2FkIGEgRG9jdW1lbnQgW29ubH'
+    'kgSFRUUF3SAQRmaWxlMhN7InBlcnNvbl9pZCI6ICIxIiB9QgwKCl9wZXJzb25faWRCCgoIX21h'
+    'aWxfaWQ=');
+
+@$core.Deprecated('Use uploadDocumentResponseDescriptor instead')
+const UploadDocumentResponse$json = {
+  '1': 'UploadDocumentResponse',
+  '2': [
+    {'1': 'document', '3': 1, '4': 1, '5': 11, '6': '.pb.Document', '10': 'document'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `UploadDocumentResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List uploadDocumentResponseDescriptor = $convert.base64Decode(
+    'ChZVcGxvYWREb2N1bWVudFJlc3BvbnNlEigKCGRvY3VtZW50GAEgASgLMgwucGIuRG9jdW1lbn'
+    'RSCGRvY3VtZW50Oh6SQRsKGSoXVXBsb2FkRG9jdW1lbnQgUmVzcG9uc2U=');
+
diff --git a/frontend/app/lib/pb/rpc_upload_document.pbserver.dart b/frontend/app/lib/pb/rpc_upload_document.pbserver.dart
new file mode 100644
index 0000000..437b306
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_upload_document.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_upload_document.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_upload_document.pb.dart';
+
diff --git a/frontend/app/lib/pb/rpc_verify_email.pb.dart b/frontend/app/lib/pb/rpc_verify_email.pb.dart
new file mode 100644
index 0000000..8abd8d4
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_verify_email.pb.dart
@@ -0,0 +1,133 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_verify_email.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+class VerifyEmailRequest extends $pb.GeneratedMessage {
+  factory VerifyEmailRequest({
+    $fixnum.Int64? accountId,
+    $core.String? secretKey,
+  }) {
+    final $result = create();
+    if (accountId != null) {
+      $result.accountId = accountId;
+    }
+    if (secretKey != null) {
+      $result.secretKey = secretKey;
+    }
+    return $result;
+  }
+  VerifyEmailRequest._() : super();
+  factory VerifyEmailRequest.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory VerifyEmailRequest.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'VerifyEmailRequest', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'accountId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..aOS(2, _omitFieldNames ? '' : 'secretKey')
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  VerifyEmailRequest clone() => VerifyEmailRequest()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  VerifyEmailRequest copyWith(void Function(VerifyEmailRequest) updates) => super.copyWith((message) => updates(message as VerifyEmailRequest)) as VerifyEmailRequest;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static VerifyEmailRequest create() => VerifyEmailRequest._();
+  VerifyEmailRequest createEmptyInstance() => create();
+  static $pb.PbList<VerifyEmailRequest> createRepeated() => $pb.PbList<VerifyEmailRequest>();
+  @$core.pragma('dart2js:noInline')
+  static VerifyEmailRequest getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<VerifyEmailRequest>(create);
+  static VerifyEmailRequest? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $fixnum.Int64 get accountId => $_getI64(0);
+  @$pb.TagNumber(1)
+  set accountId($fixnum.Int64 v) { $_setInt64(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasAccountId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearAccountId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $core.String get secretKey => $_getSZ(1);
+  @$pb.TagNumber(2)
+  set secretKey($core.String v) { $_setString(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasSecretKey() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearSecretKey() => clearField(2);
+}
+
+class VerifyEmailResponse extends $pb.GeneratedMessage {
+  factory VerifyEmailResponse({
+    $core.bool? verified,
+  }) {
+    final $result = create();
+    if (verified != null) {
+      $result.verified = verified;
+    }
+    return $result;
+  }
+  VerifyEmailResponse._() : super();
+  factory VerifyEmailResponse.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory VerifyEmailResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'VerifyEmailResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOB(1, _omitFieldNames ? '' : 'verified')
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  VerifyEmailResponse clone() => VerifyEmailResponse()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  VerifyEmailResponse copyWith(void Function(VerifyEmailResponse) updates) => super.copyWith((message) => updates(message as VerifyEmailResponse)) as VerifyEmailResponse;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static VerifyEmailResponse create() => VerifyEmailResponse._();
+  VerifyEmailResponse createEmptyInstance() => create();
+  static $pb.PbList<VerifyEmailResponse> createRepeated() => $pb.PbList<VerifyEmailResponse>();
+  @$core.pragma('dart2js:noInline')
+  static VerifyEmailResponse getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<VerifyEmailResponse>(create);
+  static VerifyEmailResponse? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.bool get verified => $_getBF(0);
+  @$pb.TagNumber(1)
+  set verified($core.bool v) { $_setBool(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasVerified() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearVerified() => clearField(1);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/rpc_verify_email.pbenum.dart b/frontend/app/lib/pb/rpc_verify_email.pbenum.dart
new file mode 100644
index 0000000..e28cbf3
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_verify_email.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_verify_email.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/rpc_verify_email.pbjson.dart b/frontend/app/lib/pb/rpc_verify_email.pbjson.dart
new file mode 100644
index 0000000..a96bf98
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_verify_email.pbjson.dart
@@ -0,0 +1,46 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_verify_email.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use verifyEmailRequestDescriptor instead')
+const VerifyEmailRequest$json = {
+  '1': 'VerifyEmailRequest',
+  '2': [
+    {'1': 'account_id', '3': 1, '4': 1, '5': 4, '10': 'accountId'},
+    {'1': 'secret_key', '3': 2, '4': 1, '5': 9, '10': 'secretKey'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `VerifyEmailRequest`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List verifyEmailRequestDescriptor = $convert.base64Decode(
+    'ChJWZXJpZnlFbWFpbFJlcXVlc3QSHQoKYWNjb3VudF9pZBgBIAEoBFIJYWNjb3VudElkEh0KCn'
+    'NlY3JldF9rZXkYAiABKAlSCXNlY3JldEtleTpckkFZCicqC1ZlcmlmeUVtYWls0gEKYWNjb3Vu'
+    'dF9pZNIBCnNlY3JldF9rZXkyLnsiaWQiOiAiMSIsICJzZWNyZXRfa2V5IjogInRoaXNpc2FzZW'
+    'NyZXRrZXkiIH0=');
+
+@$core.Deprecated('Use verifyEmailResponseDescriptor instead')
+const VerifyEmailResponse$json = {
+  '1': 'VerifyEmailResponse',
+  '2': [
+    {'1': 'verified', '3': 1, '4': 1, '5': 8, '8': {}, '10': 'verified'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `VerifyEmailResponse`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List verifyEmailResponseDescriptor = $convert.base64Decode(
+    'ChNWZXJpZnlFbWFpbFJlc3BvbnNlEh8KCHZlcmlmaWVkGAEgASgIQgOSQQBSCHZlcmlmaWVkOh'
+    'uSQRgKFioUVmVyaWZ5RW1haWwgUmVzcG9uc2U=');
+
diff --git a/frontend/app/lib/pb/rpc_verify_email.pbserver.dart b/frontend/app/lib/pb/rpc_verify_email.pbserver.dart
new file mode 100644
index 0000000..2c1e023
--- /dev/null
+++ b/frontend/app/lib/pb/rpc_verify_email.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: rpc_verify_email.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'rpc_verify_email.pb.dart';
+
diff --git a/frontend/app/lib/pb/service_df.pb.dart b/frontend/app/lib/pb/service_df.pb.dart
new file mode 100644
index 0000000..6ee0f7a
--- /dev/null
+++ b/frontend/app/lib/pb/service_df.pb.dart
@@ -0,0 +1,131 @@
+//
+//  Generated code. Do not modify.
+//  source: service_df.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:async' as $async;
+import 'dart:core' as $core;
+
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'rpc_block_session.pb.dart' as $11;
+import 'rpc_create_account.pb.dart' as $14;
+import 'rpc_create_account_info.pb.dart' as $18;
+import 'rpc_create_payment.pb.dart' as $26;
+import 'rpc_create_person.pb.dart' as $21;
+import 'rpc_delete_document.pb.dart' as $33;
+import 'rpc_delete_payment.pb.dart' as $28;
+import 'rpc_delete_person.pb.dart' as $24;
+import 'rpc_get_account.pb.dart' as $12;
+import 'rpc_get_account_info.pb.dart' as $16;
+import 'rpc_get_payment.pb.dart' as $27;
+import 'rpc_get_person.pb.dart' as $23;
+import 'rpc_list_account_info.pb.dart' as $17;
+import 'rpc_list_accounts.pb.dart' as $13;
+import 'rpc_list_payments.pb.dart' as $29;
+import 'rpc_list_persons.pb.dart' as $25;
+import 'rpc_list_returns_log_by_person_id.pb.dart' as $31;
+import 'rpc_list_sessions.pb.dart' as $10;
+import 'rpc_login.pb.dart' as $8;
+import 'rpc_refresh_token.pb.dart' as $9;
+import 'rpc_update_account.pb.dart' as $15;
+import 'rpc_update_account_info.pb.dart' as $19;
+import 'rpc_update_account_privacy.pb.dart' as $20;
+import 'rpc_update_payment.pb.dart' as $30;
+import 'rpc_update_person.pb.dart' as $22;
+import 'rpc_upload_document.pb.dart' as $32;
+import 'rpc_verify_email.pb.dart' as $34;
+
+class dfApi {
+  $pb.RpcClient _client;
+  dfApi(this._client);
+
+  $async.Future<$8.LoginResponse> login($pb.ClientContext? ctx, $8.LoginRequest request) =>
+    _client.invoke<$8.LoginResponse>(ctx, 'df', 'Login', request, $8.LoginResponse())
+  ;
+  $async.Future<$9.RefreshTokenResponse> refreshToken($pb.ClientContext? ctx, $9.RefreshTokenRequest request) =>
+    _client.invoke<$9.RefreshTokenResponse>(ctx, 'df', 'RefreshToken', request, $9.RefreshTokenResponse())
+  ;
+  $async.Future<$10.ListSessionsResponse> listSessions($pb.ClientContext? ctx, $10.ListSessionsRequest request) =>
+    _client.invoke<$10.ListSessionsResponse>(ctx, 'df', 'ListSessions', request, $10.ListSessionsResponse())
+  ;
+  $async.Future<$11.BlockSessionResponse> blockSession($pb.ClientContext? ctx, $11.BlockSessionRequest request) =>
+    _client.invoke<$11.BlockSessionResponse>(ctx, 'df', 'BlockSession', request, $11.BlockSessionResponse())
+  ;
+  $async.Future<$12.GetAccountResponse> getAccount($pb.ClientContext? ctx, $12.GetAccountRequest request) =>
+    _client.invoke<$12.GetAccountResponse>(ctx, 'df', 'GetAccount', request, $12.GetAccountResponse())
+  ;
+  $async.Future<$13.ListAccountsResponse> listAccounts($pb.ClientContext? ctx, $13.ListAccountsRequest request) =>
+    _client.invoke<$13.ListAccountsResponse>(ctx, 'df', 'ListAccounts', request, $13.ListAccountsResponse())
+  ;
+  $async.Future<$14.CreateAccountResponse> createAccount($pb.ClientContext? ctx, $14.CreateAccountRequest request) =>
+    _client.invoke<$14.CreateAccountResponse>(ctx, 'df', 'CreateAccount', request, $14.CreateAccountResponse())
+  ;
+  $async.Future<$15.UpdateAccountResponse> updateAccount($pb.ClientContext? ctx, $15.UpdateAccountRequest request) =>
+    _client.invoke<$15.UpdateAccountResponse>(ctx, 'df', 'UpdateAccount', request, $15.UpdateAccountResponse())
+  ;
+  $async.Future<$16.GetAccountInfoResponse> getAccountInfo($pb.ClientContext? ctx, $16.GetAccountInfoRequest request) =>
+    _client.invoke<$16.GetAccountInfoResponse>(ctx, 'df', 'GetAccountInfo', request, $16.GetAccountInfoResponse())
+  ;
+  $async.Future<$17.ListAccountInfoResponse> listAccountInfo($pb.ClientContext? ctx, $17.ListAccountInfoRequest request) =>
+    _client.invoke<$17.ListAccountInfoResponse>(ctx, 'df', 'ListAccountInfo', request, $17.ListAccountInfoResponse())
+  ;
+  $async.Future<$18.CreateAccountInfoResponse> createAccountInfo($pb.ClientContext? ctx, $18.CreateAccountInfoRequest request) =>
+    _client.invoke<$18.CreateAccountInfoResponse>(ctx, 'df', 'CreateAccountInfo', request, $18.CreateAccountInfoResponse())
+  ;
+  $async.Future<$19.UpdateAccountInfoResponse> updateAccountInfo($pb.ClientContext? ctx, $19.UpdateAccountInfoRequest request) =>
+    _client.invoke<$19.UpdateAccountInfoResponse>(ctx, 'df', 'UpdateAccountInfo', request, $19.UpdateAccountInfoResponse())
+  ;
+  $async.Future<$20.UpdateAccountPrivacyResponse> updateAccountPrivacy($pb.ClientContext? ctx, $20.UpdateAccountPrivacyRequest request) =>
+    _client.invoke<$20.UpdateAccountPrivacyResponse>(ctx, 'df', 'UpdateAccountPrivacy', request, $20.UpdateAccountPrivacyResponse())
+  ;
+  $async.Future<$21.CreatePersonResponse> createPerson($pb.ClientContext? ctx, $21.CreatePersonRequest request) =>
+    _client.invoke<$21.CreatePersonResponse>(ctx, 'df', 'CreatePerson', request, $21.CreatePersonResponse())
+  ;
+  $async.Future<$22.UpdatePersonResponse> updatePerson($pb.ClientContext? ctx, $22.UpdatePersonRequest request) =>
+    _client.invoke<$22.UpdatePersonResponse>(ctx, 'df', 'UpdatePerson', request, $22.UpdatePersonResponse())
+  ;
+  $async.Future<$23.GetPersonResponse> getPerson($pb.ClientContext? ctx, $23.GetPersonRequest request) =>
+    _client.invoke<$23.GetPersonResponse>(ctx, 'df', 'GetPerson', request, $23.GetPersonResponse())
+  ;
+  $async.Future<$24.DeletePersonResponse> deletePerson($pb.ClientContext? ctx, $24.DeletePersonRequest request) =>
+    _client.invoke<$24.DeletePersonResponse>(ctx, 'df', 'DeletePerson', request, $24.DeletePersonResponse())
+  ;
+  $async.Future<$25.ListPersonsResponse> listPersons($pb.ClientContext? ctx, $25.ListPersonsRequest request) =>
+    _client.invoke<$25.ListPersonsResponse>(ctx, 'df', 'ListPersons', request, $25.ListPersonsResponse())
+  ;
+  $async.Future<$26.CreatePaymentResponse> createPayment($pb.ClientContext? ctx, $26.CreatePaymentRequest request) =>
+    _client.invoke<$26.CreatePaymentResponse>(ctx, 'df', 'CreatePayment', request, $26.CreatePaymentResponse())
+  ;
+  $async.Future<$27.GetPaymentResponse> getPayment($pb.ClientContext? ctx, $27.GetPaymentRequest request) =>
+    _client.invoke<$27.GetPaymentResponse>(ctx, 'df', 'GetPayment', request, $27.GetPaymentResponse())
+  ;
+  $async.Future<$28.DeletePaymentResponse> deletePayment($pb.ClientContext? ctx, $28.DeletePaymentRequest request) =>
+    _client.invoke<$28.DeletePaymentResponse>(ctx, 'df', 'DeletePayment', request, $28.DeletePaymentResponse())
+  ;
+  $async.Future<$29.ListPaymentsResponse> listPayments($pb.ClientContext? ctx, $29.ListPaymentsRequest request) =>
+    _client.invoke<$29.ListPaymentsResponse>(ctx, 'df', 'ListPayments', request, $29.ListPaymentsResponse())
+  ;
+  $async.Future<$30.UpdatePaymentResponse> updatePayment($pb.ClientContext? ctx, $30.UpdatePaymentRequest request) =>
+    _client.invoke<$30.UpdatePaymentResponse>(ctx, 'df', 'UpdatePayment', request, $30.UpdatePaymentResponse())
+  ;
+  $async.Future<$31.ListReturnsLogResponse> listReturnsLog($pb.ClientContext? ctx, $31.ListReturnsLogRequest request) =>
+    _client.invoke<$31.ListReturnsLogResponse>(ctx, 'df', 'ListReturnsLog', request, $31.ListReturnsLogResponse())
+  ;
+  $async.Future<$32.UploadDocumentResponse> uploadDocument($pb.ClientContext? ctx, $32.UploadDocumentRequest request) =>
+    _client.invoke<$32.UploadDocumentResponse>(ctx, 'df', 'UploadDocument', request, $32.UploadDocumentResponse())
+  ;
+  $async.Future<$33.DeleteDocumentResponse> deleteDocument($pb.ClientContext? ctx, $33.DeleteDocumentRequest request) =>
+    _client.invoke<$33.DeleteDocumentResponse>(ctx, 'df', 'DeleteDocument', request, $33.DeleteDocumentResponse())
+  ;
+  $async.Future<$34.VerifyEmailResponse> verifyEmail($pb.ClientContext? ctx, $34.VerifyEmailRequest request) =>
+    _client.invoke<$34.VerifyEmailResponse>(ctx, 'df', 'VerifyEmail', request, $34.VerifyEmailResponse())
+  ;
+}
+
diff --git a/frontend/app/lib/pb/service_df.pbenum.dart b/frontend/app/lib/pb/service_df.pbenum.dart
new file mode 100644
index 0000000..0f470fe
--- /dev/null
+++ b/frontend/app/lib/pb/service_df.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: service_df.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/service_df.pbjson.dart b/frontend/app/lib/pb/service_df.pbjson.dart
new file mode 100644
index 0000000..1ff1c56
--- /dev/null
+++ b/frontend/app/lib/pb/service_df.pbjson.dart
@@ -0,0 +1,232 @@
+//
+//  Generated code. Do not modify.
+//  source: service_df.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+import 'account.pbjson.dart' as $2;
+import 'account_info.pbjson.dart' as $1;
+import 'document.pbjson.dart' as $7;
+import 'google/protobuf/timestamp.pbjson.dart' as $0;
+import 'payment.pbjson.dart' as $3;
+import 'person.pbjson.dart' as $4;
+import 'returns_log.pbjson.dart' as $5;
+import 'rpc_block_session.pbjson.dart' as $11;
+import 'rpc_create_account.pbjson.dart' as $14;
+import 'rpc_create_account_info.pbjson.dart' as $18;
+import 'rpc_create_payment.pbjson.dart' as $26;
+import 'rpc_create_person.pbjson.dart' as $21;
+import 'rpc_delete_document.pbjson.dart' as $33;
+import 'rpc_delete_payment.pbjson.dart' as $28;
+import 'rpc_delete_person.pbjson.dart' as $24;
+import 'rpc_get_account.pbjson.dart' as $12;
+import 'rpc_get_account_info.pbjson.dart' as $16;
+import 'rpc_get_payment.pbjson.dart' as $27;
+import 'rpc_get_person.pbjson.dart' as $23;
+import 'rpc_list_account_info.pbjson.dart' as $17;
+import 'rpc_list_accounts.pbjson.dart' as $13;
+import 'rpc_list_payments.pbjson.dart' as $29;
+import 'rpc_list_persons.pbjson.dart' as $25;
+import 'rpc_list_returns_log_by_person_id.pbjson.dart' as $31;
+import 'rpc_list_sessions.pbjson.dart' as $10;
+import 'rpc_login.pbjson.dart' as $8;
+import 'rpc_refresh_token.pbjson.dart' as $9;
+import 'rpc_update_account.pbjson.dart' as $15;
+import 'rpc_update_account_info.pbjson.dart' as $19;
+import 'rpc_update_account_privacy.pbjson.dart' as $20;
+import 'rpc_update_payment.pbjson.dart' as $30;
+import 'rpc_update_person.pbjson.dart' as $22;
+import 'rpc_upload_document.pbjson.dart' as $32;
+import 'rpc_verify_email.pbjson.dart' as $34;
+import 'session.pbjson.dart' as $6;
+
+const $core.Map<$core.String, $core.dynamic> dfServiceBase$json = {
+  '1': 'df',
+  '2': [
+    {'1': 'Login', '2': '.pb.LoginRequest', '3': '.pb.LoginResponse', '4': {}},
+    {'1': 'RefreshToken', '2': '.pb.RefreshTokenRequest', '3': '.pb.RefreshTokenResponse', '4': {}},
+    {'1': 'ListSessions', '2': '.pb.ListSessionsRequest', '3': '.pb.ListSessionsResponse', '4': {}},
+    {'1': 'BlockSession', '2': '.pb.BlockSessionRequest', '3': '.pb.BlockSessionResponse', '4': {}},
+    {'1': 'GetAccount', '2': '.pb.GetAccountRequest', '3': '.pb.GetAccountResponse', '4': {}},
+    {'1': 'ListAccounts', '2': '.pb.ListAccountsRequest', '3': '.pb.ListAccountsResponse', '4': {}},
+    {'1': 'CreateAccount', '2': '.pb.CreateAccountRequest', '3': '.pb.CreateAccountResponse', '4': {}},
+    {'1': 'UpdateAccount', '2': '.pb.UpdateAccountRequest', '3': '.pb.UpdateAccountResponse', '4': {}},
+    {'1': 'GetAccountInfo', '2': '.pb.GetAccountInfoRequest', '3': '.pb.GetAccountInfoResponse', '4': {}},
+    {'1': 'ListAccountInfo', '2': '.pb.ListAccountInfoRequest', '3': '.pb.ListAccountInfoResponse', '4': {}},
+    {'1': 'CreateAccountInfo', '2': '.pb.CreateAccountInfoRequest', '3': '.pb.CreateAccountInfoResponse', '4': {}},
+    {'1': 'UpdateAccountInfo', '2': '.pb.UpdateAccountInfoRequest', '3': '.pb.UpdateAccountInfoResponse', '4': {}},
+    {'1': 'UpdateAccountPrivacy', '2': '.pb.UpdateAccountPrivacyRequest', '3': '.pb.UpdateAccountPrivacyResponse', '4': {}},
+    {'1': 'CreatePerson', '2': '.pb.CreatePersonRequest', '3': '.pb.CreatePersonResponse', '4': {}},
+    {'1': 'UpdatePerson', '2': '.pb.UpdatePersonRequest', '3': '.pb.UpdatePersonResponse', '4': {}},
+    {'1': 'GetPerson', '2': '.pb.GetPersonRequest', '3': '.pb.GetPersonResponse', '4': {}},
+    {'1': 'DeletePerson', '2': '.pb.DeletePersonRequest', '3': '.pb.DeletePersonResponse', '4': {}},
+    {'1': 'ListPersons', '2': '.pb.ListPersonsRequest', '3': '.pb.ListPersonsResponse', '4': {}},
+    {'1': 'CreatePayment', '2': '.pb.CreatePaymentRequest', '3': '.pb.CreatePaymentResponse', '4': {}},
+    {'1': 'GetPayment', '2': '.pb.GetPaymentRequest', '3': '.pb.GetPaymentResponse', '4': {}},
+    {'1': 'DeletePayment', '2': '.pb.DeletePaymentRequest', '3': '.pb.DeletePaymentResponse', '4': {}},
+    {'1': 'ListPayments', '2': '.pb.ListPaymentsRequest', '3': '.pb.ListPaymentsResponse', '4': {}},
+    {'1': 'UpdatePayment', '2': '.pb.UpdatePaymentRequest', '3': '.pb.UpdatePaymentResponse', '4': {}},
+    {'1': 'ListReturnsLog', '2': '.pb.ListReturnsLogRequest', '3': '.pb.ListReturnsLogResponse', '4': {}},
+    {'1': 'UploadDocument', '2': '.pb.UploadDocumentRequest', '3': '.pb.UploadDocumentResponse', '4': {}},
+    {'1': 'DeleteDocument', '2': '.pb.DeleteDocumentRequest', '3': '.pb.DeleteDocumentResponse', '4': {}},
+    {'1': 'VerifyEmail', '2': '.pb.VerifyEmailRequest', '3': '.pb.VerifyEmailResponse', '4': {}},
+  ],
+  '3': {},
+};
+
+@$core.Deprecated('Use dfServiceDescriptor instead')
+const $core.Map<$core.String, $core.Map<$core.String, $core.dynamic>> dfServiceBase$messageJson = {
+  '.pb.LoginRequest': $8.LoginRequest$json,
+  '.pb.LoginResponse': $8.LoginResponse$json,
+  '.google.protobuf.Timestamp': $0.Timestamp$json,
+  '.pb.RefreshTokenRequest': $9.RefreshTokenRequest$json,
+  '.pb.RefreshTokenResponse': $9.RefreshTokenResponse$json,
+  '.pb.ListSessionsRequest': $10.ListSessionsRequest$json,
+  '.pb.ListSessionsResponse': $10.ListSessionsResponse$json,
+  '.pb.Session': $6.Session$json,
+  '.pb.BlockSessionRequest': $11.BlockSessionRequest$json,
+  '.pb.BlockSessionResponse': $11.BlockSessionResponse$json,
+  '.pb.GetAccountRequest': $12.GetAccountRequest$json,
+  '.pb.GetAccountResponse': $12.GetAccountResponse$json,
+  '.pb.Account': $2.Account$json,
+  '.pb.ListAccountsRequest': $13.ListAccountsRequest$json,
+  '.pb.ListAccountsResponse': $13.ListAccountsResponse$json,
+  '.pb.CreateAccountRequest': $14.CreateAccountRequest$json,
+  '.pb.CreateAccountResponse': $14.CreateAccountResponse$json,
+  '.pb.UpdateAccountRequest': $15.UpdateAccountRequest$json,
+  '.pb.UpdateAccountResponse': $15.UpdateAccountResponse$json,
+  '.pb.GetAccountInfoRequest': $16.GetAccountInfoRequest$json,
+  '.pb.GetAccountInfoResponse': $16.GetAccountInfoResponse$json,
+  '.pb.AccountInfo': $1.AccountInfo$json,
+  '.pb.ListAccountInfoRequest': $17.ListAccountInfoRequest$json,
+  '.pb.ListAccountInfoResponse': $17.ListAccountInfoResponse$json,
+  '.pb.CreateAccountInfoRequest': $18.CreateAccountInfoRequest$json,
+  '.pb.CreateAccountInfoResponse': $18.CreateAccountInfoResponse$json,
+  '.pb.UpdateAccountInfoRequest': $19.UpdateAccountInfoRequest$json,
+  '.pb.UpdateAccountInfoResponse': $19.UpdateAccountInfoResponse$json,
+  '.pb.UpdateAccountPrivacyRequest': $20.UpdateAccountPrivacyRequest$json,
+  '.pb.UpdateAccountPrivacyResponse': $20.UpdateAccountPrivacyResponse$json,
+  '.pb.CreatePersonRequest': $21.CreatePersonRequest$json,
+  '.pb.CreatePersonResponse': $21.CreatePersonResponse$json,
+  '.pb.Person': $4.Person$json,
+  '.pb.UpdatePersonRequest': $22.UpdatePersonRequest$json,
+  '.pb.UpdatePersonResponse': $22.UpdatePersonResponse$json,
+  '.pb.GetPersonRequest': $23.GetPersonRequest$json,
+  '.pb.GetPersonResponse': $23.GetPersonResponse$json,
+  '.pb.DeletePersonRequest': $24.DeletePersonRequest$json,
+  '.pb.DeletePersonResponse': $24.DeletePersonResponse$json,
+  '.pb.ListPersonsRequest': $25.ListPersonsRequest$json,
+  '.pb.ListPersonsResponse': $25.ListPersonsResponse$json,
+  '.pb.CreatePaymentRequest': $26.CreatePaymentRequest$json,
+  '.pb.CreatePaymentResponse': $26.CreatePaymentResponse$json,
+  '.pb.Payment': $3.Payment$json,
+  '.pb.GetPaymentRequest': $27.GetPaymentRequest$json,
+  '.pb.GetPaymentResponse': $27.GetPaymentResponse$json,
+  '.pb.DeletePaymentRequest': $28.DeletePaymentRequest$json,
+  '.pb.DeletePaymentResponse': $28.DeletePaymentResponse$json,
+  '.pb.ListPaymentsRequest': $29.ListPaymentsRequest$json,
+  '.pb.ListPaymentsResponse': $29.ListPaymentsResponse$json,
+  '.pb.UpdatePaymentRequest': $30.UpdatePaymentRequest$json,
+  '.pb.UpdatePaymentResponse': $30.UpdatePaymentResponse$json,
+  '.pb.ListReturnsLogRequest': $31.ListReturnsLogRequest$json,
+  '.pb.ListReturnsLogResponse': $31.ListReturnsLogResponse$json,
+  '.pb.ReturnsLog': $5.ReturnsLog$json,
+  '.pb.UploadDocumentRequest': $32.UploadDocumentRequest$json,
+  '.pb.UploadDocumentResponse': $32.UploadDocumentResponse$json,
+  '.pb.Document': $7.Document$json,
+  '.pb.DeleteDocumentRequest': $33.DeleteDocumentRequest$json,
+  '.pb.DeleteDocumentResponse': $33.DeleteDocumentResponse$json,
+  '.pb.VerifyEmailRequest': $34.VerifyEmailRequest$json,
+  '.pb.VerifyEmailResponse': $34.VerifyEmailResponse$json,
+};
+
+/// Descriptor for `df`. Decode as a `google.protobuf.ServiceDescriptorProto`.
+final $typed_data.Uint8List dfServiceDescriptor = $convert.base64Decode(
+    'CgJkZhJCCgVMb2dpbhIQLnBiLkxvZ2luUmVxdWVzdBoRLnBiLkxvZ2luUmVzcG9uc2UiFILT5J'
+    'MCDiIJL3YxL2xvZ2luOgEqEmgKDFJlZnJlc2hUb2tlbhIXLnBiLlJlZnJlc2hUb2tlblJlcXVl'
+    'c3QaGC5wYi5SZWZyZXNoVG9rZW5SZXNwb25zZSIlgtPkkwIfIhovdjEvc2Vzc2lvbnMvcmVmcm'
+    'VzaF90b2tlbjoBKhKkAQoMTGlzdFNlc3Npb25zEhcucGIuTGlzdFNlc3Npb25zUmVxdWVzdBoY'
+    'LnBiLkxpc3RTZXNzaW9uc1Jlc3BvbnNlImGSQS8SG0xpc3QgU2Vzc2lvbnMgYnkgYWNjb3VudF'
+    '9pZGIQCg4KCkJlYXJlckF1dGgSAILT5JMCKRInL3YxL3Nlc3Npb25zL2xpc3Rfc2Vzc2lvbnMv'
+    'e2FjY291bnRfaWR9EpIBCgxCbG9ja1Nlc3Npb24SFy5wYi5CbG9ja1Nlc3Npb25SZXF1ZXN0Gh'
+    'gucGIuQmxvY2tTZXNzaW9uUmVzcG9uc2UiT5JBJxITQmxvY2sgU2Vzc2lvbiBieSBJRGIQCg4K'
+    'CkJlYXJlckF1dGgSAILT5JMCHzIaL3YxL3Nlc3Npb25zL2Jsb2NrX3Nlc3Npb246ASoSkgEKCk'
+    'dldEFjY291bnQSFS5wYi5HZXRBY2NvdW50UmVxdWVzdBoWLnBiLkdldEFjY291bnRSZXNwb25z'
+    'ZSJVkkEtEhlHZXQgQWNjb3VudCBieSBhY2NvdW50X2lkYhAKDgoKQmVhcmVyQXV0aBIAgtPkkw'
+    'IfEh0vdjEvYWNjb3VudHMvZ2V0X2FjY291bnQve2lkfRKWAQoMTGlzdEFjY291bnRzEhcucGIu'
+    'TGlzdEFjY291bnRzUmVxdWVzdBoYLnBiLkxpc3RBY2NvdW50c1Jlc3BvbnNlIlOSQS4SGkxpc3'
+    'QgQWNjb3VudHMgW2FkbWluIG9ubHldYhAKDgoKQmVhcmVyQXV0aBIAgtPkkwIcEhovdjEvYWNj'
+    'b3VudHMvbGlzdF9hY2NvdW50cxKDAQoNQ3JlYXRlQWNjb3VudBIYLnBiLkNyZWF0ZUFjY291bn'
+    'RSZXF1ZXN0GhkucGIuQ3JlYXRlQWNjb3VudFJlc3BvbnNlIj2SQRQSEkNyZWF0ZSBBY2NvdW50'
+    'SW5mb4LT5JMCICIbL3YxL2FjY291bnRzL2NyZWF0ZV9hY2NvdW50OgEqEpEBCg1VcGRhdGVBY2'
+    'NvdW50EhgucGIuVXBkYXRlQWNjb3VudFJlcXVlc3QaGS5wYi5VcGRhdGVBY2NvdW50UmVzcG9u'
+    'c2UiS5JBIhIOVXBkYXRlIEFjY291bnRiEAoOCgpCZWFyZXJBdXRoEgCC0+STAiAyGy92MS9hY2'
+    'NvdW50cy91cGRhdGVfYWNjb3VudDoBKhKvAQoOR2V0QWNjb3VudEluZm8SGS5wYi5HZXRBY2Nv'
+    'dW50SW5mb1JlcXVlc3QaGi5wYi5HZXRBY2NvdW50SW5mb1Jlc3BvbnNlImaSQTESHUdldCBBY2'
+    'NvdW50SW5mbyBieSBhY2NvdW50X2lkYhAKDgoKQmVhcmVyQXV0aBIAgtPkkwIsEiovdjEvYWNj'
+    'b3VudHMvZ2V0X2FjY291bnRfaW5mby97YWNjb3VudF9pZH0SpwEKD0xpc3RBY2NvdW50SW5mbx'
+    'IaLnBiLkxpc3RBY2NvdW50SW5mb1JlcXVlc3QaGy5wYi5MaXN0QWNjb3VudEluZm9SZXNwb25z'
+    'ZSJbkkEyEh5MaXN0IEFjY291bnRJbmZvcyBbYWRtaW4gb25seV1iEAoOCgpCZWFyZXJBdXRoEg'
+    'CC0+STAiASHi92MS9hY2NvdW50cy9saXN0X2FjY291bnRfaW5mbxKmAQoRQ3JlYXRlQWNjb3Vu'
+    'dEluZm8SHC5wYi5DcmVhdGVBY2NvdW50SW5mb1JlcXVlc3QaHS5wYi5DcmVhdGVBY2NvdW50SW'
+    '5mb1Jlc3BvbnNlIlSSQSYSEkNyZWF0ZSBBY2NvdW50SW5mb2IQCg4KCkJlYXJlckF1dGgSAILT'
+    '5JMCJSIgL3YxL2FjY291bnRzL2NyZWF0ZV9hY2NvdW50X2luZm86ASoSpgEKEVVwZGF0ZUFjY2'
+    '91bnRJbmZvEhwucGIuVXBkYXRlQWNjb3VudEluZm9SZXF1ZXN0Gh0ucGIuVXBkYXRlQWNjb3Vu'
+    'dEluZm9SZXNwb25zZSJUkkEmEhJVcGRhdGUgQWNjb3VudEluZm9iEAoOCgpCZWFyZXJBdXRoEg'
+    'CC0+STAiUyIC92MS9hY2NvdW50cy91cGRhdGVfYWNjb3VudF9pbmZvOgEqEr8BChRVcGRhdGVB'
+    'Y2NvdW50UHJpdmFjeRIfLnBiLlVwZGF0ZUFjY291bnRQcml2YWN5UmVxdWVzdBogLnBiLlVwZG'
+    'F0ZUFjY291bnRQcml2YWN5UmVzcG9uc2UiZJJBMxIfVXBkYXRlIEFjY291bnQgUHJpdmFjeSBT'
+    'ZXR0aW5nc2IQCg4KCkJlYXJlckF1dGgSAILT5JMCKDIjL3YxL2FjY291bnRzL3VwZGF0ZV9hY2'
+    'NvdW50X3ByaXZhY3k6ASoSiwEKDENyZWF0ZVBlcnNvbhIXLnBiLkNyZWF0ZVBlcnNvblJlcXVl'
+    'c3QaGC5wYi5DcmVhdGVQZXJzb25SZXNwb25zZSJIkkEhEg1DcmVhdGUgUGVyc29uYhAKDgoKQm'
+    'VhcmVyQXV0aBIAgtPkkwIeIhkvdjEvcGVyc29ucy9jcmVhdGVfcGVyc29uOgEqEosBCgxVcGRh'
+    'dGVQZXJzb24SFy5wYi5VcGRhdGVQZXJzb25SZXF1ZXN0GhgucGIuVXBkYXRlUGVyc29uUmVzcG'
+    '9uc2UiSJJBIRINVXBkYXRlIFBlcnNvbmIQCg4KCkJlYXJlckF1dGgSAILT5JMCHjIZL3YxL3Bl'
+    'cnNvbnMvdXBkYXRlX3BlcnNvbjoBKhKEAQoJR2V0UGVyc29uEhQucGIuR2V0UGVyc29uUmVxdW'
+    'VzdBoVLnBiLkdldFBlcnNvblJlc3BvbnNlIkqSQSQSEEdldCBQZXJzb24gYnkgSURiEAoOCgpC'
+    'ZWFyZXJBdXRoEgCC0+STAh0SGy92MS9wZXJzb25zL2dldF9wZXJzb24ve2lkfRKTAQoMRGVsZX'
+    'RlUGVyc29uEhcucGIuRGVsZXRlUGVyc29uUmVxdWVzdBoYLnBiLkRlbGV0ZVBlcnNvblJlc3Bv'
+    'bnNlIlCSQScSE0RlbGV0ZSBQZXJzb24gYnkgSURiEAoOCgpCZWFyZXJBdXRoEgCC0+STAiAqHi'
+    '92MS9wZXJzb25zL2RlbGV0ZV9wZXJzb24ve2lkfRKeAQoLTGlzdFBlcnNvbnMSFi5wYi5MaXN0'
+    'UGVyc29uc1JlcXVlc3QaFy5wYi5MaXN0UGVyc29uc1Jlc3BvbnNlIl6SQS4SGkxpc3QgUGVyc2'
+    '9ucyBieSBhY2NvdW50X2lkYhAKDgoKQmVhcmVyQXV0aBIAgtPkkwInEiUvdjEvcGVyc29ucy9s'
+    'aXN0X3BlcnNvbnMve2FjY291bnRfaWR9EpEBCg1DcmVhdGVQYXltZW50EhgucGIuQ3JlYXRlUG'
+    'F5bWVudFJlcXVlc3QaGS5wYi5DcmVhdGVQYXltZW50UmVzcG9uc2UiS5JBIhIOQ3JlYXRlIFBh'
+    'eW1lbnRiEAoOCgpCZWFyZXJBdXRoEgCC0+STAiAiGy92MS9wYXltZW50cy9jcmVhdGVfcGF5bW'
+    'VudDoBKhKKAQoKR2V0UGF5bWVudBIVLnBiLkdldFBheW1lbnRSZXF1ZXN0GhYucGIuR2V0UGF5'
+    'bWVudFJlc3BvbnNlIk2SQSUSEUdldCBQYXltZW50IGJ5IElEYhAKDgoKQmVhcmVyQXV0aBIAgt'
+    'PkkwIfEh0vdjEvcGF5bWVudHMvZ2V0X3BheW1lbnQve2lkfRKZAQoNRGVsZXRlUGF5bWVudBIY'
+    'LnBiLkRlbGV0ZVBheW1lbnRSZXF1ZXN0GhkucGIuRGVsZXRlUGF5bWVudFJlc3BvbnNlIlOSQS'
+    'gSFERlbGV0ZSBQYXltZW50IGJ5IElEYhAKDgoKQmVhcmVyQXV0aBIAgtPkkwIiKiAvdjEvcGF5'
+    'bWVudHMvZGVsZXRlX3BheW1lbnQve2lkfRKkAQoMTGlzdFBheW1lbnRzEhcucGIuTGlzdFBheW'
+    '1lbnRzUmVxdWVzdBoYLnBiLkxpc3RQYXltZW50c1Jlc3BvbnNlImGSQS8SG0xpc3QgUGF5bWVu'
+    'dHMgYnkgYWNjb3VudF9pZGIQCg4KCkJlYXJlckF1dGgSAILT5JMCKRInL3YxL3BheW1lbnRzL2'
+    'xpc3RfcGF5bWVudHMve2FjY291bnRfaWR9EpEBCg1VcGRhdGVQYXltZW50EhgucGIuVXBkYXRl'
+    'UGF5bWVudFJlcXVlc3QaGS5wYi5VcGRhdGVQYXltZW50UmVzcG9uc2UiS5JBIhIOVXBkYXRlIF'
+    'BheW1lbnRiEAoOCgpCZWFyZXJBdXRoEgCC0+STAiAyGy92MS9wYXltZW50cy91cGRhdGVfcGF5'
+    'bWVudDoBKhKwAQoOTGlzdFJldHVybnNMb2cSGS5wYi5MaXN0UmV0dXJuc0xvZ1JlcXVlc3QaGi'
+    '5wYi5MaXN0UmV0dXJuc0xvZ1Jlc3BvbnNlImeSQTASHExpc3QgUmV0dXJuc0xvZyBieSBwZXJz'
+    'b25faWRiEAoOCgpCZWFyZXJBdXRoEgCC0+STAi4SLC92MS9yZXR1cm5zX2xvZy9saXN0X3JldH'
+    'VybnNfbG9nL3twZXJzb25faWR9EsoCCg5VcGxvYWREb2N1bWVudBIZLnBiLlVwbG9hZERvY3Vt'
+    'ZW50UmVxdWVzdBoaLnBiLlVwbG9hZERvY3VtZW50UmVzcG9uc2UigAKSQeABEhtVcGxvYWQgRG'
+    '9jdW1lbnQgW29ubHkgSFRUUF0argFUZXN0aW5nIHZpYSBzd2FnZ2VyIGlzIG5vdCBwb3NzaWJs'
+    'ZS4gVHJ5IGBgYGN1cmwgLVggUE9TVCAtSCAiQXV0aG9yaXphdGlvbjogQmVhcmVyIHt0b2tlbn'
+    '0iIC1GICJmaWxlPUAvcGF0aC90by9maWxlIiAtRiAicGVyc29uX2lkPTEiICJodHRwOi8ve3Nl'
+    'cnZlclVSSX0vZG9jdW1lbnRzL3VwbG9hZCJgYGBiEAoOCgpCZWFyZXJBdXRoEgCC0+STAhYiES'
+    '9kb2N1bWVudHMvdXBsb2FkOgEqEp8BCg5EZWxldGVEb2N1bWVudBIZLnBiLkRlbGV0ZURvY3Vt'
+    'ZW50UmVxdWVzdBoaLnBiLkRlbGV0ZURvY3VtZW50UmVzcG9uc2UiVpJBKRIVRGVsZXRlIERvY3'
+    'VtZW50IGJ5IElEYhAKDgoKQmVhcmVyQXV0aBIAgtPkkwIkKiIvdjEvZG9jdW1lbnRzL2RlbGV0'
+    'ZV9kb2N1bWVudC97aWR9EqIBCgtWZXJpZnlFbWFpbBIWLnBiLlZlcmlmeUVtYWlsUmVxdWVzdB'
+    'oXLnBiLlZlcmlmeUVtYWlsUmVzcG9uc2UiYpJBLRIrVmVyaWZ5IEVtYWlsIHdpdGggYWNjb3Vu'
+    'dF9pZCBhbmQgc2VjcmV0X2tleYLT5JMCLBIqL3YxL3ZlcmlmeV9lbWFpbC97YWNjb3VudF9pZH'
+    '0ve3NlY3JldF9rZXl9GgeSQQQSAmRm');
+
diff --git a/frontend/app/lib/pb/service_df.pbserver.dart b/frontend/app/lib/pb/service_df.pbserver.dart
new file mode 100644
index 0000000..6ed842d
--- /dev/null
+++ b/frontend/app/lib/pb/service_df.pbserver.dart
@@ -0,0 +1,147 @@
+//
+//  Generated code. Do not modify.
+//  source: service_df.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:async' as $async;
+import 'dart:core' as $core;
+
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'rpc_block_session.pb.dart' as $11;
+import 'rpc_create_account.pb.dart' as $14;
+import 'rpc_create_account_info.pb.dart' as $18;
+import 'rpc_create_payment.pb.dart' as $26;
+import 'rpc_create_person.pb.dart' as $21;
+import 'rpc_delete_document.pb.dart' as $33;
+import 'rpc_delete_payment.pb.dart' as $28;
+import 'rpc_delete_person.pb.dart' as $24;
+import 'rpc_get_account.pb.dart' as $12;
+import 'rpc_get_account_info.pb.dart' as $16;
+import 'rpc_get_payment.pb.dart' as $27;
+import 'rpc_get_person.pb.dart' as $23;
+import 'rpc_list_account_info.pb.dart' as $17;
+import 'rpc_list_accounts.pb.dart' as $13;
+import 'rpc_list_payments.pb.dart' as $29;
+import 'rpc_list_persons.pb.dart' as $25;
+import 'rpc_list_returns_log_by_person_id.pb.dart' as $31;
+import 'rpc_list_sessions.pb.dart' as $10;
+import 'rpc_login.pb.dart' as $8;
+import 'rpc_refresh_token.pb.dart' as $9;
+import 'rpc_update_account.pb.dart' as $15;
+import 'rpc_update_account_info.pb.dart' as $19;
+import 'rpc_update_account_privacy.pb.dart' as $20;
+import 'rpc_update_payment.pb.dart' as $30;
+import 'rpc_update_person.pb.dart' as $22;
+import 'rpc_upload_document.pb.dart' as $32;
+import 'rpc_verify_email.pb.dart' as $34;
+import 'service_df.pbjson.dart';
+
+export 'service_df.pb.dart';
+
+abstract class dfServiceBase extends $pb.GeneratedService {
+  $async.Future<$8.LoginResponse> login($pb.ServerContext ctx, $8.LoginRequest request);
+  $async.Future<$9.RefreshTokenResponse> refreshToken($pb.ServerContext ctx, $9.RefreshTokenRequest request);
+  $async.Future<$10.ListSessionsResponse> listSessions($pb.ServerContext ctx, $10.ListSessionsRequest request);
+  $async.Future<$11.BlockSessionResponse> blockSession($pb.ServerContext ctx, $11.BlockSessionRequest request);
+  $async.Future<$12.GetAccountResponse> getAccount($pb.ServerContext ctx, $12.GetAccountRequest request);
+  $async.Future<$13.ListAccountsResponse> listAccounts($pb.ServerContext ctx, $13.ListAccountsRequest request);
+  $async.Future<$14.CreateAccountResponse> createAccount($pb.ServerContext ctx, $14.CreateAccountRequest request);
+  $async.Future<$15.UpdateAccountResponse> updateAccount($pb.ServerContext ctx, $15.UpdateAccountRequest request);
+  $async.Future<$16.GetAccountInfoResponse> getAccountInfo($pb.ServerContext ctx, $16.GetAccountInfoRequest request);
+  $async.Future<$17.ListAccountInfoResponse> listAccountInfo($pb.ServerContext ctx, $17.ListAccountInfoRequest request);
+  $async.Future<$18.CreateAccountInfoResponse> createAccountInfo($pb.ServerContext ctx, $18.CreateAccountInfoRequest request);
+  $async.Future<$19.UpdateAccountInfoResponse> updateAccountInfo($pb.ServerContext ctx, $19.UpdateAccountInfoRequest request);
+  $async.Future<$20.UpdateAccountPrivacyResponse> updateAccountPrivacy($pb.ServerContext ctx, $20.UpdateAccountPrivacyRequest request);
+  $async.Future<$21.CreatePersonResponse> createPerson($pb.ServerContext ctx, $21.CreatePersonRequest request);
+  $async.Future<$22.UpdatePersonResponse> updatePerson($pb.ServerContext ctx, $22.UpdatePersonRequest request);
+  $async.Future<$23.GetPersonResponse> getPerson($pb.ServerContext ctx, $23.GetPersonRequest request);
+  $async.Future<$24.DeletePersonResponse> deletePerson($pb.ServerContext ctx, $24.DeletePersonRequest request);
+  $async.Future<$25.ListPersonsResponse> listPersons($pb.ServerContext ctx, $25.ListPersonsRequest request);
+  $async.Future<$26.CreatePaymentResponse> createPayment($pb.ServerContext ctx, $26.CreatePaymentRequest request);
+  $async.Future<$27.GetPaymentResponse> getPayment($pb.ServerContext ctx, $27.GetPaymentRequest request);
+  $async.Future<$28.DeletePaymentResponse> deletePayment($pb.ServerContext ctx, $28.DeletePaymentRequest request);
+  $async.Future<$29.ListPaymentsResponse> listPayments($pb.ServerContext ctx, $29.ListPaymentsRequest request);
+  $async.Future<$30.UpdatePaymentResponse> updatePayment($pb.ServerContext ctx, $30.UpdatePaymentRequest request);
+  $async.Future<$31.ListReturnsLogResponse> listReturnsLog($pb.ServerContext ctx, $31.ListReturnsLogRequest request);
+  $async.Future<$32.UploadDocumentResponse> uploadDocument($pb.ServerContext ctx, $32.UploadDocumentRequest request);
+  $async.Future<$33.DeleteDocumentResponse> deleteDocument($pb.ServerContext ctx, $33.DeleteDocumentRequest request);
+  $async.Future<$34.VerifyEmailResponse> verifyEmail($pb.ServerContext ctx, $34.VerifyEmailRequest request);
+
+  $pb.GeneratedMessage createRequest($core.String methodName) {
+    switch (methodName) {
+      case 'Login': return $8.LoginRequest();
+      case 'RefreshToken': return $9.RefreshTokenRequest();
+      case 'ListSessions': return $10.ListSessionsRequest();
+      case 'BlockSession': return $11.BlockSessionRequest();
+      case 'GetAccount': return $12.GetAccountRequest();
+      case 'ListAccounts': return $13.ListAccountsRequest();
+      case 'CreateAccount': return $14.CreateAccountRequest();
+      case 'UpdateAccount': return $15.UpdateAccountRequest();
+      case 'GetAccountInfo': return $16.GetAccountInfoRequest();
+      case 'ListAccountInfo': return $17.ListAccountInfoRequest();
+      case 'CreateAccountInfo': return $18.CreateAccountInfoRequest();
+      case 'UpdateAccountInfo': return $19.UpdateAccountInfoRequest();
+      case 'UpdateAccountPrivacy': return $20.UpdateAccountPrivacyRequest();
+      case 'CreatePerson': return $21.CreatePersonRequest();
+      case 'UpdatePerson': return $22.UpdatePersonRequest();
+      case 'GetPerson': return $23.GetPersonRequest();
+      case 'DeletePerson': return $24.DeletePersonRequest();
+      case 'ListPersons': return $25.ListPersonsRequest();
+      case 'CreatePayment': return $26.CreatePaymentRequest();
+      case 'GetPayment': return $27.GetPaymentRequest();
+      case 'DeletePayment': return $28.DeletePaymentRequest();
+      case 'ListPayments': return $29.ListPaymentsRequest();
+      case 'UpdatePayment': return $30.UpdatePaymentRequest();
+      case 'ListReturnsLog': return $31.ListReturnsLogRequest();
+      case 'UploadDocument': return $32.UploadDocumentRequest();
+      case 'DeleteDocument': return $33.DeleteDocumentRequest();
+      case 'VerifyEmail': return $34.VerifyEmailRequest();
+      default: throw $core.ArgumentError('Unknown method: $methodName');
+    }
+  }
+
+  $async.Future<$pb.GeneratedMessage> handleCall($pb.ServerContext ctx, $core.String methodName, $pb.GeneratedMessage request) {
+    switch (methodName) {
+      case 'Login': return this.login(ctx, request as $8.LoginRequest);
+      case 'RefreshToken': return this.refreshToken(ctx, request as $9.RefreshTokenRequest);
+      case 'ListSessions': return this.listSessions(ctx, request as $10.ListSessionsRequest);
+      case 'BlockSession': return this.blockSession(ctx, request as $11.BlockSessionRequest);
+      case 'GetAccount': return this.getAccount(ctx, request as $12.GetAccountRequest);
+      case 'ListAccounts': return this.listAccounts(ctx, request as $13.ListAccountsRequest);
+      case 'CreateAccount': return this.createAccount(ctx, request as $14.CreateAccountRequest);
+      case 'UpdateAccount': return this.updateAccount(ctx, request as $15.UpdateAccountRequest);
+      case 'GetAccountInfo': return this.getAccountInfo(ctx, request as $16.GetAccountInfoRequest);
+      case 'ListAccountInfo': return this.listAccountInfo(ctx, request as $17.ListAccountInfoRequest);
+      case 'CreateAccountInfo': return this.createAccountInfo(ctx, request as $18.CreateAccountInfoRequest);
+      case 'UpdateAccountInfo': return this.updateAccountInfo(ctx, request as $19.UpdateAccountInfoRequest);
+      case 'UpdateAccountPrivacy': return this.updateAccountPrivacy(ctx, request as $20.UpdateAccountPrivacyRequest);
+      case 'CreatePerson': return this.createPerson(ctx, request as $21.CreatePersonRequest);
+      case 'UpdatePerson': return this.updatePerson(ctx, request as $22.UpdatePersonRequest);
+      case 'GetPerson': return this.getPerson(ctx, request as $23.GetPersonRequest);
+      case 'DeletePerson': return this.deletePerson(ctx, request as $24.DeletePersonRequest);
+      case 'ListPersons': return this.listPersons(ctx, request as $25.ListPersonsRequest);
+      case 'CreatePayment': return this.createPayment(ctx, request as $26.CreatePaymentRequest);
+      case 'GetPayment': return this.getPayment(ctx, request as $27.GetPaymentRequest);
+      case 'DeletePayment': return this.deletePayment(ctx, request as $28.DeletePaymentRequest);
+      case 'ListPayments': return this.listPayments(ctx, request as $29.ListPaymentsRequest);
+      case 'UpdatePayment': return this.updatePayment(ctx, request as $30.UpdatePaymentRequest);
+      case 'ListReturnsLog': return this.listReturnsLog(ctx, request as $31.ListReturnsLogRequest);
+      case 'UploadDocument': return this.uploadDocument(ctx, request as $32.UploadDocumentRequest);
+      case 'DeleteDocument': return this.deleteDocument(ctx, request as $33.DeleteDocumentRequest);
+      case 'VerifyEmail': return this.verifyEmail(ctx, request as $34.VerifyEmailRequest);
+      default: throw $core.ArgumentError('Unknown method: $methodName');
+    }
+  }
+
+  $core.Map<$core.String, $core.dynamic> get $json => dfServiceBase$json;
+  $core.Map<$core.String, $core.Map<$core.String, $core.dynamic>> get $messageJson => dfServiceBase$messageJson;
+}
+
diff --git a/frontend/app/lib/pb/session.pb.dart b/frontend/app/lib/pb/session.pb.dart
new file mode 100644
index 0000000..d41a3ba
--- /dev/null
+++ b/frontend/app/lib/pb/session.pb.dart
@@ -0,0 +1,173 @@
+//
+//  Generated code. Do not modify.
+//  source: session.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:fixnum/fixnum.dart' as $fixnum;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'google/protobuf/timestamp.pb.dart' as $0;
+
+class Session extends $pb.GeneratedMessage {
+  factory Session({
+    $core.String? id,
+    $fixnum.Int64? accountId,
+    $core.String? userAgent,
+    $core.String? clientIp,
+    $core.bool? isBlocked,
+    $0.Timestamp? expiresAt,
+    $core.String? refreshToken,
+    $0.Timestamp? createdAt,
+  }) {
+    final $result = create();
+    if (id != null) {
+      $result.id = id;
+    }
+    if (accountId != null) {
+      $result.accountId = accountId;
+    }
+    if (userAgent != null) {
+      $result.userAgent = userAgent;
+    }
+    if (clientIp != null) {
+      $result.clientIp = clientIp;
+    }
+    if (isBlocked != null) {
+      $result.isBlocked = isBlocked;
+    }
+    if (expiresAt != null) {
+      $result.expiresAt = expiresAt;
+    }
+    if (refreshToken != null) {
+      $result.refreshToken = refreshToken;
+    }
+    if (createdAt != null) {
+      $result.createdAt = createdAt;
+    }
+    return $result;
+  }
+  Session._() : super();
+  factory Session.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
+  factory Session.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'Session', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
+    ..aOS(1, _omitFieldNames ? '' : 'id')
+    ..a<$fixnum.Int64>(2, _omitFieldNames ? '' : 'accountId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
+    ..aOS(3, _omitFieldNames ? '' : 'userAgent')
+    ..aOS(4, _omitFieldNames ? '' : 'clientIp')
+    ..aOB(5, _omitFieldNames ? '' : 'isBlocked')
+    ..aOM<$0.Timestamp>(6, _omitFieldNames ? '' : 'expiresAt', subBuilder: $0.Timestamp.create)
+    ..aOS(7, _omitFieldNames ? '' : 'refreshToken')
+    ..aOM<$0.Timestamp>(8, _omitFieldNames ? '' : 'createdAt', subBuilder: $0.Timestamp.create)
+    ..hasRequiredFields = false
+  ;
+
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
+  'Will be removed in next major version')
+  Session clone() => Session()..mergeFromMessage(this);
+  @$core.Deprecated(
+  'Using this can add significant overhead to your binary. '
+  'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
+  'Will be removed in next major version')
+  Session copyWith(void Function(Session) updates) => super.copyWith((message) => updates(message as Session)) as Session;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static Session create() => Session._();
+  Session createEmptyInstance() => create();
+  static $pb.PbList<Session> createRepeated() => $pb.PbList<Session>();
+  @$core.pragma('dart2js:noInline')
+  static Session getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<Session>(create);
+  static Session? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $core.String get id => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set id($core.String v) { $_setString(0, v); }
+  @$pb.TagNumber(1)
+  $core.bool hasId() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearId() => clearField(1);
+
+  @$pb.TagNumber(2)
+  $fixnum.Int64 get accountId => $_getI64(1);
+  @$pb.TagNumber(2)
+  set accountId($fixnum.Int64 v) { $_setInt64(1, v); }
+  @$pb.TagNumber(2)
+  $core.bool hasAccountId() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearAccountId() => clearField(2);
+
+  @$pb.TagNumber(3)
+  $core.String get userAgent => $_getSZ(2);
+  @$pb.TagNumber(3)
+  set userAgent($core.String v) { $_setString(2, v); }
+  @$pb.TagNumber(3)
+  $core.bool hasUserAgent() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearUserAgent() => clearField(3);
+
+  @$pb.TagNumber(4)
+  $core.String get clientIp => $_getSZ(3);
+  @$pb.TagNumber(4)
+  set clientIp($core.String v) { $_setString(3, v); }
+  @$pb.TagNumber(4)
+  $core.bool hasClientIp() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearClientIp() => clearField(4);
+
+  @$pb.TagNumber(5)
+  $core.bool get isBlocked => $_getBF(4);
+  @$pb.TagNumber(5)
+  set isBlocked($core.bool v) { $_setBool(4, v); }
+  @$pb.TagNumber(5)
+  $core.bool hasIsBlocked() => $_has(4);
+  @$pb.TagNumber(5)
+  void clearIsBlocked() => clearField(5);
+
+  @$pb.TagNumber(6)
+  $0.Timestamp get expiresAt => $_getN(5);
+  @$pb.TagNumber(6)
+  set expiresAt($0.Timestamp v) { setField(6, v); }
+  @$pb.TagNumber(6)
+  $core.bool hasExpiresAt() => $_has(5);
+  @$pb.TagNumber(6)
+  void clearExpiresAt() => clearField(6);
+  @$pb.TagNumber(6)
+  $0.Timestamp ensureExpiresAt() => $_ensure(5);
+
+  @$pb.TagNumber(7)
+  $core.String get refreshToken => $_getSZ(6);
+  @$pb.TagNumber(7)
+  set refreshToken($core.String v) { $_setString(6, v); }
+  @$pb.TagNumber(7)
+  $core.bool hasRefreshToken() => $_has(6);
+  @$pb.TagNumber(7)
+  void clearRefreshToken() => clearField(7);
+
+  @$pb.TagNumber(8)
+  $0.Timestamp get createdAt => $_getN(7);
+  @$pb.TagNumber(8)
+  set createdAt($0.Timestamp v) { setField(8, v); }
+  @$pb.TagNumber(8)
+  $core.bool hasCreatedAt() => $_has(7);
+  @$pb.TagNumber(8)
+  void clearCreatedAt() => clearField(8);
+  @$pb.TagNumber(8)
+  $0.Timestamp ensureCreatedAt() => $_ensure(7);
+}
+
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/frontend/app/lib/pb/session.pbenum.dart b/frontend/app/lib/pb/session.pbenum.dart
new file mode 100644
index 0000000..d515787
--- /dev/null
+++ b/frontend/app/lib/pb/session.pbenum.dart
@@ -0,0 +1,11 @@
+//
+//  Generated code. Do not modify.
+//  source: session.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
diff --git a/frontend/app/lib/pb/session.pbjson.dart b/frontend/app/lib/pb/session.pbjson.dart
new file mode 100644
index 0000000..830202c
--- /dev/null
+++ b/frontend/app/lib/pb/session.pbjson.dart
@@ -0,0 +1,51 @@
+//
+//  Generated code. Do not modify.
+//  source: session.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:convert' as $convert;
+import 'dart:core' as $core;
+import 'dart:typed_data' as $typed_data;
+
+@$core.Deprecated('Use sessionDescriptor instead')
+const Session$json = {
+  '1': 'Session',
+  '2': [
+    {'1': 'id', '3': 1, '4': 1, '5': 9, '10': 'id'},
+    {'1': 'account_id', '3': 2, '4': 1, '5': 4, '10': 'accountId'},
+    {'1': 'user_agent', '3': 3, '4': 1, '5': 9, '10': 'userAgent'},
+    {'1': 'client_ip', '3': 4, '4': 1, '5': 9, '10': 'clientIp'},
+    {'1': 'is_blocked', '3': 5, '4': 1, '5': 8, '10': 'isBlocked'},
+    {'1': 'expires_at', '3': 6, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'expiresAt'},
+    {'1': 'created_at', '3': 8, '4': 1, '5': 11, '6': '.google.protobuf.Timestamp', '8': {}, '10': 'createdAt'},
+    {'1': 'refresh_token', '3': 7, '4': 1, '5': 9, '10': 'refreshToken'},
+  ],
+  '7': {},
+};
+
+/// Descriptor for `Session`. Decode as a `google.protobuf.DescriptorProto`.
+final $typed_data.Uint8List sessionDescriptor = $convert.base64Decode(
+    'CgdTZXNzaW9uEg4KAmlkGAEgASgJUgJpZBIdCgphY2NvdW50X2lkGAIgASgEUglhY2NvdW50SW'
+    'QSHQoKdXNlcl9hZ2VudBgDIAEoCVIJdXNlckFnZW50EhsKCWNsaWVudF9pcBgEIAEoCVIIY2xp'
+    'ZW50SXASHQoKaXNfYmxvY2tlZBgFIAEoCFIJaXNCbG9ja2VkElYKCmV4cGlyZXNfYXQYBiABKA'
+    'syGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wQhuSQRhKFiIxOTkwLTEwLTA1VDAwOjAwOjAw'
+    'WiJSCWV4cGlyZXNBdBJWCgpjcmVhdGVkX2F0GAggASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbW'
+    'VzdGFtcEIbkkEYShYiMTk5MC0xMC0wNVQwMDowMDowMFoiUgljcmVhdGVkQXQSIwoNcmVmcmVz'
+    'aF90b2tlbhgHIAEoCVIMcmVmcmVzaFRva2VuOp0EkkGZBAoJKgdTZXNzaW9uMosEeyJpZCI6IC'
+    'IxIiwiYWNjb3VudF9pZCI6ICIxIiwgInJlZnJlc2hfdG9rZW4iOiAidjQucHVibGljLmV5Smxi'
+    'V0ZwYkNJNkltRXlRR0l1WkdVaUxDSmxlSEFpT2lJeU1ESXpMVEV3TFRBMlZEQXhPakF5T2pBNU'
+    't6QXlPakF3SWl3aWFXRjBJam9pTWpBeU15MHhNQzB3TlZRd01Ub3dNam93T1Nzd01qb3dNQ0lz'
+    'SW1sa0lqb2lOV1V4WkRZM1pHRXROMk01WWkwME16WTFMV0UwWkRVdE0yTmpNR0V3TlRFeU5ERm'
+    'xJaXdpYm1KbUlqb2lNakF5TXkweE1DMHdOVlF3TVRvd01qb3dPU3N3TWpvd01DSjlCb1gzNncw'
+    'cG8xdnZIU2pzQlBfS1dlRnhWMXhSYlFheXFiSnVJb0syaktxeTFCdDJSb0h5SmJMb0NFTzE1Q1'
+    'JUNURuUTZQMEFIbEJ6anNYdDYxYUREdyIsICJleHBpcmVzX2F0IjogIjIwMjMtMTAtMDVUMDI6'
+    'MzA6NTNaIiwgImNyZWF0ZWRfYXQiOiAiMjAyMy0xMC0wNVQwMToyMDoxMVoiLCAiY2xpZW50X2'
+    'lwIjogIjEwLjU2LjAuMTIiLCAidXNlcl9hZ2VudCI6ICJNb3ppbGxhIEZpcmVmb3giLCAiaXNf'
+    'YmxvY2tlZCI6IGZhbHNlfQ==');
+
diff --git a/frontend/app/lib/pb/session.pbserver.dart b/frontend/app/lib/pb/session.pbserver.dart
new file mode 100644
index 0000000..79ba84d
--- /dev/null
+++ b/frontend/app/lib/pb/session.pbserver.dart
@@ -0,0 +1,14 @@
+//
+//  Generated code. Do not modify.
+//  source: session.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names
+// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+export 'session.pb.dart';
+
diff --git a/frontend/app/linux/.gitignore b/frontend/app/linux/.gitignore
new file mode 100644
index 0000000..d3896c9
--- /dev/null
+++ b/frontend/app/linux/.gitignore
@@ -0,0 +1 @@
+flutter/ephemeral
diff --git a/frontend/app/linux/CMakeLists.txt b/frontend/app/linux/CMakeLists.txt
new file mode 100644
index 0000000..c21918f
--- /dev/null
+++ b/frontend/app/linux/CMakeLists.txt
@@ -0,0 +1,139 @@
+# Project-level configuration.
+cmake_minimum_required(VERSION 3.10)
+project(runner LANGUAGES CXX)
+
+# The name of the executable created for the application. Change this to change
+# the on-disk name of your application.
+set(BINARY_NAME "app")
+# The unique GTK application identifier for this application. See:
+# https://wiki.gnome.org/HowDoI/ChooseApplicationID
+set(APPLICATION_ID "com.example.app")
+
+# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
+# versions of CMake.
+cmake_policy(SET CMP0063 NEW)
+
+# Load bundled libraries from the lib/ directory relative to the binary.
+set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
+
+# Root filesystem for cross-building.
+if(FLUTTER_TARGET_PLATFORM_SYSROOT)
+  set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
+  set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
+  set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+  set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
+  set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+  set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+endif()
+
+# Define build configuration options.
+if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+  set(CMAKE_BUILD_TYPE "Debug" CACHE
+    STRING "Flutter build mode" FORCE)
+  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
+    "Debug" "Profile" "Release")
+endif()
+
+# Compilation settings that should be applied to most targets.
+#
+# Be cautious about adding new options here, as plugins use this function by
+# default. In most cases, you should add new options to specific targets instead
+# of modifying this function.
+function(APPLY_STANDARD_SETTINGS TARGET)
+  target_compile_features(${TARGET} PUBLIC cxx_std_14)
+  target_compile_options(${TARGET} PRIVATE -Wall -Werror)
+  target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
+  target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
+endfunction()
+
+# Flutter library and tool build rules.
+set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
+add_subdirectory(${FLUTTER_MANAGED_DIR})
+
+# System-level dependencies.
+find_package(PkgConfig REQUIRED)
+pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
+
+add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
+
+# Define the application target. To change its name, change BINARY_NAME above,
+# not the value here, or `flutter run` will no longer work.
+#
+# Any new source files that you add to the application should be added here.
+add_executable(${BINARY_NAME}
+  "main.cc"
+  "my_application.cc"
+  "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
+)
+
+# Apply the standard set of build settings. This can be removed for applications
+# that need different build settings.
+apply_standard_settings(${BINARY_NAME})
+
+# Add dependency libraries. Add any application-specific dependencies here.
+target_link_libraries(${BINARY_NAME} PRIVATE flutter)
+target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
+
+# Run the Flutter tool portions of the build. This must not be removed.
+add_dependencies(${BINARY_NAME} flutter_assemble)
+
+# Only the install-generated bundle's copy of the executable will launch
+# correctly, since the resources must in the right relative locations. To avoid
+# people trying to run the unbundled copy, put it in a subdirectory instead of
+# the default top-level location.
+set_target_properties(${BINARY_NAME}
+  PROPERTIES
+  RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
+)
+
+
+# Generated plugin build rules, which manage building the plugins and adding
+# them to the application.
+include(flutter/generated_plugins.cmake)
+
+
+# === Installation ===
+# By default, "installing" just makes a relocatable bundle in the build
+# directory.
+set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
+if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+  set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
+endif()
+
+# Start with a clean build bundle directory every time.
+install(CODE "
+  file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
+  " COMPONENT Runtime)
+
+set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
+set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
+
+install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
+  COMPONENT Runtime)
+
+install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
+  COMPONENT Runtime)
+
+install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
+  COMPONENT Runtime)
+
+foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
+  install(FILES "${bundled_library}"
+    DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
+    COMPONENT Runtime)
+endforeach(bundled_library)
+
+# Fully re-copy the assets directory on each build to avoid having stale files
+# from a previous install.
+set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
+install(CODE "
+  file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
+  " COMPONENT Runtime)
+install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
+  DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
+
+# Install the AOT library on non-Debug builds only.
+if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
+  install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
+    COMPONENT Runtime)
+endif()
diff --git a/frontend/app/linux/flutter/CMakeLists.txt b/frontend/app/linux/flutter/CMakeLists.txt
new file mode 100644
index 0000000..d5bd016
--- /dev/null
+++ b/frontend/app/linux/flutter/CMakeLists.txt
@@ -0,0 +1,88 @@
+# This file controls Flutter-level build steps. It should not be edited.
+cmake_minimum_required(VERSION 3.10)
+
+set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
+
+# Configuration provided via flutter tool.
+include(${EPHEMERAL_DIR}/generated_config.cmake)
+
+# TODO: Move the rest of this into files in ephemeral. See
+# https://github.com/flutter/flutter/issues/57146.
+
+# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
+# which isn't available in 3.10.
+function(list_prepend LIST_NAME PREFIX)
+    set(NEW_LIST "")
+    foreach(element ${${LIST_NAME}})
+        list(APPEND NEW_LIST "${PREFIX}${element}")
+    endforeach(element)
+    set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
+endfunction()
+
+# === Flutter Library ===
+# System-level dependencies.
+find_package(PkgConfig REQUIRED)
+pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
+pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
+pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
+
+set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
+
+# Published to parent scope for install step.
+set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
+set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
+set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
+set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
+
+list(APPEND FLUTTER_LIBRARY_HEADERS
+  "fl_basic_message_channel.h"
+  "fl_binary_codec.h"
+  "fl_binary_messenger.h"
+  "fl_dart_project.h"
+  "fl_engine.h"
+  "fl_json_message_codec.h"
+  "fl_json_method_codec.h"
+  "fl_message_codec.h"
+  "fl_method_call.h"
+  "fl_method_channel.h"
+  "fl_method_codec.h"
+  "fl_method_response.h"
+  "fl_plugin_registrar.h"
+  "fl_plugin_registry.h"
+  "fl_standard_message_codec.h"
+  "fl_standard_method_codec.h"
+  "fl_string_codec.h"
+  "fl_value.h"
+  "fl_view.h"
+  "flutter_linux.h"
+)
+list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
+add_library(flutter INTERFACE)
+target_include_directories(flutter INTERFACE
+  "${EPHEMERAL_DIR}"
+)
+target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
+target_link_libraries(flutter INTERFACE
+  PkgConfig::GTK
+  PkgConfig::GLIB
+  PkgConfig::GIO
+)
+add_dependencies(flutter flutter_assemble)
+
+# === Flutter tool backend ===
+# _phony_ is a non-existent file to force this command to run every time,
+# since currently there's no way to get a full input/output list from the
+# flutter tool.
+add_custom_command(
+  OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
+    ${CMAKE_CURRENT_BINARY_DIR}/_phony_
+  COMMAND ${CMAKE_COMMAND} -E env
+    ${FLUTTER_TOOL_ENVIRONMENT}
+    "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
+      ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
+  VERBATIM
+)
+add_custom_target(flutter_assemble DEPENDS
+  "${FLUTTER_LIBRARY}"
+  ${FLUTTER_LIBRARY_HEADERS}
+)
diff --git a/frontend/app/linux/flutter/generated_plugin_registrant.cc b/frontend/app/linux/flutter/generated_plugin_registrant.cc
new file mode 100644
index 0000000..e71a16d
--- /dev/null
+++ b/frontend/app/linux/flutter/generated_plugin_registrant.cc
@@ -0,0 +1,11 @@
+//
+//  Generated file. Do not edit.
+//
+
+// clang-format off
+
+#include "generated_plugin_registrant.h"
+
+
+void fl_register_plugins(FlPluginRegistry* registry) {
+}
diff --git a/frontend/app/linux/flutter/generated_plugin_registrant.h b/frontend/app/linux/flutter/generated_plugin_registrant.h
new file mode 100644
index 0000000..e0f0a47
--- /dev/null
+++ b/frontend/app/linux/flutter/generated_plugin_registrant.h
@@ -0,0 +1,15 @@
+//
+//  Generated file. Do not edit.
+//
+
+// clang-format off
+
+#ifndef GENERATED_PLUGIN_REGISTRANT_
+#define GENERATED_PLUGIN_REGISTRANT_
+
+#include <flutter_linux/flutter_linux.h>
+
+// Registers Flutter plugins.
+void fl_register_plugins(FlPluginRegistry* registry);
+
+#endif  // GENERATED_PLUGIN_REGISTRANT_
diff --git a/frontend/app/linux/flutter/generated_plugins.cmake b/frontend/app/linux/flutter/generated_plugins.cmake
new file mode 100644
index 0000000..2e1de87
--- /dev/null
+++ b/frontend/app/linux/flutter/generated_plugins.cmake
@@ -0,0 +1,23 @@
+#
+# Generated file, do not edit.
+#
+
+list(APPEND FLUTTER_PLUGIN_LIST
+)
+
+list(APPEND FLUTTER_FFI_PLUGIN_LIST
+)
+
+set(PLUGIN_BUNDLED_LIBRARIES)
+
+foreach(plugin ${FLUTTER_PLUGIN_LIST})
+  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
+  target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
+  list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
+  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
+endforeach(plugin)
+
+foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
+  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
+  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
+endforeach(ffi_plugin)
diff --git a/frontend/app/linux/main.cc b/frontend/app/linux/main.cc
new file mode 100644
index 0000000..e7c5c54
--- /dev/null
+++ b/frontend/app/linux/main.cc
@@ -0,0 +1,6 @@
+#include "my_application.h"
+
+int main(int argc, char** argv) {
+  g_autoptr(MyApplication) app = my_application_new();
+  return g_application_run(G_APPLICATION(app), argc, argv);
+}
diff --git a/frontend/app/linux/my_application.cc b/frontend/app/linux/my_application.cc
new file mode 100644
index 0000000..42d9b08
--- /dev/null
+++ b/frontend/app/linux/my_application.cc
@@ -0,0 +1,104 @@
+#include "my_application.h"
+
+#include <flutter_linux/flutter_linux.h>
+#ifdef GDK_WINDOWING_X11
+#include <gdk/gdkx.h>
+#endif
+
+#include "flutter/generated_plugin_registrant.h"
+
+struct _MyApplication {
+  GtkApplication parent_instance;
+  char** dart_entrypoint_arguments;
+};
+
+G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
+
+// Implements GApplication::activate.
+static void my_application_activate(GApplication* application) {
+  MyApplication* self = MY_APPLICATION(application);
+  GtkWindow* window =
+      GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
+
+  // Use a header bar when running in GNOME as this is the common style used
+  // by applications and is the setup most users will be using (e.g. Ubuntu
+  // desktop).
+  // If running on X and not using GNOME then just use a traditional title bar
+  // in case the window manager does more exotic layout, e.g. tiling.
+  // If running on Wayland assume the header bar will work (may need changing
+  // if future cases occur).
+  gboolean use_header_bar = TRUE;
+#ifdef GDK_WINDOWING_X11
+  GdkScreen* screen = gtk_window_get_screen(window);
+  if (GDK_IS_X11_SCREEN(screen)) {
+    const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
+    if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
+      use_header_bar = FALSE;
+    }
+  }
+#endif
+  if (use_header_bar) {
+    GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
+    gtk_widget_show(GTK_WIDGET(header_bar));
+    gtk_header_bar_set_title(header_bar, "app");
+    gtk_header_bar_set_show_close_button(header_bar, TRUE);
+    gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
+  } else {
+    gtk_window_set_title(window, "app");
+  }
+
+  gtk_window_set_default_size(window, 1280, 720);
+  gtk_widget_show(GTK_WIDGET(window));
+
+  g_autoptr(FlDartProject) project = fl_dart_project_new();
+  fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
+
+  FlView* view = fl_view_new(project);
+  gtk_widget_show(GTK_WIDGET(view));
+  gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
+
+  fl_register_plugins(FL_PLUGIN_REGISTRY(view));
+
+  gtk_widget_grab_focus(GTK_WIDGET(view));
+}
+
+// Implements GApplication::local_command_line.
+static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {
+  MyApplication* self = MY_APPLICATION(application);
+  // Strip out the first argument as it is the binary name.
+  self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
+
+  g_autoptr(GError) error = nullptr;
+  if (!g_application_register(application, nullptr, &error)) {
+     g_warning("Failed to register: %s", error->message);
+     *exit_status = 1;
+     return TRUE;
+  }
+
+  g_application_activate(application);
+  *exit_status = 0;
+
+  return TRUE;
+}
+
+// Implements GObject::dispose.
+static void my_application_dispose(GObject* object) {
+  MyApplication* self = MY_APPLICATION(object);
+  g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
+  G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
+}
+
+static void my_application_class_init(MyApplicationClass* klass) {
+  G_APPLICATION_CLASS(klass)->activate = my_application_activate;
+  G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
+  G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
+}
+
+static void my_application_init(MyApplication* self) {}
+
+MyApplication* my_application_new() {
+  return MY_APPLICATION(g_object_new(my_application_get_type(),
+                                     "application-id", APPLICATION_ID,
+                                     "flags", G_APPLICATION_NON_UNIQUE,
+                                     nullptr));
+}
diff --git a/frontend/app/linux/my_application.h b/frontend/app/linux/my_application.h
new file mode 100644
index 0000000..72271d5
--- /dev/null
+++ b/frontend/app/linux/my_application.h
@@ -0,0 +1,18 @@
+#ifndef FLUTTER_MY_APPLICATION_H_
+#define FLUTTER_MY_APPLICATION_H_
+
+#include <gtk/gtk.h>
+
+G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
+                     GtkApplication)
+
+/**
+ * my_application_new:
+ *
+ * Creates a new Flutter-based application.
+ *
+ * Returns: a new #MyApplication.
+ */
+MyApplication* my_application_new();
+
+#endif  // FLUTTER_MY_APPLICATION_H_
diff --git a/frontend/app/macos/.gitignore b/frontend/app/macos/.gitignore
new file mode 100644
index 0000000..746adbb
--- /dev/null
+++ b/frontend/app/macos/.gitignore
@@ -0,0 +1,7 @@
+# Flutter-related
+**/Flutter/ephemeral/
+**/Pods/
+
+# Xcode-related
+**/dgph
+**/xcuserdata/
diff --git a/frontend/app/macos/Flutter/Flutter-Debug.xcconfig b/frontend/app/macos/Flutter/Flutter-Debug.xcconfig
new file mode 100644
index 0000000..c2efd0b
--- /dev/null
+++ b/frontend/app/macos/Flutter/Flutter-Debug.xcconfig
@@ -0,0 +1 @@
+#include "ephemeral/Flutter-Generated.xcconfig"
diff --git a/frontend/app/macos/Flutter/Flutter-Release.xcconfig b/frontend/app/macos/Flutter/Flutter-Release.xcconfig
new file mode 100644
index 0000000..c2efd0b
--- /dev/null
+++ b/frontend/app/macos/Flutter/Flutter-Release.xcconfig
@@ -0,0 +1 @@
+#include "ephemeral/Flutter-Generated.xcconfig"
diff --git a/frontend/app/macos/Runner.xcodeproj/project.pbxproj b/frontend/app/macos/Runner.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..d20f4ef
--- /dev/null
+++ b/frontend/app/macos/Runner.xcodeproj/project.pbxproj
@@ -0,0 +1,695 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 54;
+	objects = {
+
+/* Begin PBXAggregateTarget section */
+		33CC111A2044C6BA0003C045 /* Flutter Assemble */ = {
+			isa = PBXAggregateTarget;
+			buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */;
+			buildPhases = (
+				33CC111E2044C6BF0003C045 /* ShellScript */,
+			);
+			dependencies = (
+			);
+			name = "Flutter Assemble";
+			productName = FLX;
+		};
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+		331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; };
+		335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
+		33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
+		33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
+		33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
+		33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+		331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 33CC10EC2044A3C60003C045;
+			remoteInfo = Runner;
+		};
+		33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 33CC111A2044C6BA0003C045;
+			remoteInfo = FLX;
+		};
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		33CC110E2044A8840003C045 /* Bundle Framework */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 10;
+			files = (
+			);
+			name = "Bundle Framework";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+		331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
+		333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
+		335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
+		33CC10ED2044A3C60003C045 /* app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "app.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+		33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
+		33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
+		33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
+		33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = "<group>"; };
+		33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = "<group>"; };
+		33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = "<group>"; };
+		33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = "<group>"; };
+		33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = "<group>"; };
+		33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
+		33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
+		33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
+		7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
+		9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		331C80D2294CF70F00263BE5 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		33CC10EA2044A3C60003C045 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		331C80D6294CF71000263BE5 /* RunnerTests */ = {
+			isa = PBXGroup;
+			children = (
+				331C80D7294CF71000263BE5 /* RunnerTests.swift */,
+			);
+			path = RunnerTests;
+			sourceTree = "<group>";
+		};
+		33BA886A226E78AF003329D5 /* Configs */ = {
+			isa = PBXGroup;
+			children = (
+				33E5194F232828860026EE4D /* AppInfo.xcconfig */,
+				9740EEB21CF90195004384FC /* Debug.xcconfig */,
+				7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
+				333000ED22D3DE5D00554162 /* Warnings.xcconfig */,
+			);
+			path = Configs;
+			sourceTree = "<group>";
+		};
+		33CC10E42044A3C60003C045 = {
+			isa = PBXGroup;
+			children = (
+				33FAB671232836740065AC1E /* Runner */,
+				33CEB47122A05771004F2AC0 /* Flutter */,
+				331C80D6294CF71000263BE5 /* RunnerTests */,
+				33CC10EE2044A3C60003C045 /* Products */,
+				D73912EC22F37F3D000D13A0 /* Frameworks */,
+			);
+			sourceTree = "<group>";
+		};
+		33CC10EE2044A3C60003C045 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				33CC10ED2044A3C60003C045 /* app.app */,
+				331C80D5294CF71000263BE5 /* RunnerTests.xctest */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		33CC11242044D66E0003C045 /* Resources */ = {
+			isa = PBXGroup;
+			children = (
+				33CC10F22044A3C60003C045 /* Assets.xcassets */,
+				33CC10F42044A3C60003C045 /* MainMenu.xib */,
+				33CC10F72044A3C60003C045 /* Info.plist */,
+			);
+			name = Resources;
+			path = ..;
+			sourceTree = "<group>";
+		};
+		33CEB47122A05771004F2AC0 /* Flutter */ = {
+			isa = PBXGroup;
+			children = (
+				335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,
+				33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,
+				33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,
+				33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */,
+			);
+			path = Flutter;
+			sourceTree = "<group>";
+		};
+		33FAB671232836740065AC1E /* Runner */ = {
+			isa = PBXGroup;
+			children = (
+				33CC10F02044A3C60003C045 /* AppDelegate.swift */,
+				33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,
+				33E51913231747F40026EE4D /* DebugProfile.entitlements */,
+				33E51914231749380026EE4D /* Release.entitlements */,
+				33CC11242044D66E0003C045 /* Resources */,
+				33BA886A226E78AF003329D5 /* Configs */,
+			);
+			path = Runner;
+			sourceTree = "<group>";
+		};
+		D73912EC22F37F3D000D13A0 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		331C80D4294CF70F00263BE5 /* RunnerTests */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
+			buildPhases = (
+				331C80D1294CF70F00263BE5 /* Sources */,
+				331C80D2294CF70F00263BE5 /* Frameworks */,
+				331C80D3294CF70F00263BE5 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				331C80DA294CF71000263BE5 /* PBXTargetDependency */,
+			);
+			name = RunnerTests;
+			productName = RunnerTests;
+			productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */;
+			productType = "com.apple.product-type.bundle.unit-test";
+		};
+		33CC10EC2044A3C60003C045 /* Runner */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
+			buildPhases = (
+				33CC10E92044A3C60003C045 /* Sources */,
+				33CC10EA2044A3C60003C045 /* Frameworks */,
+				33CC10EB2044A3C60003C045 /* Resources */,
+				33CC110E2044A8840003C045 /* Bundle Framework */,
+				3399D490228B24CF009A79C7 /* ShellScript */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				33CC11202044C79F0003C045 /* PBXTargetDependency */,
+			);
+			name = Runner;
+			productName = Runner;
+			productReference = 33CC10ED2044A3C60003C045 /* app.app */;
+			productType = "com.apple.product-type.application";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		33CC10E52044A3C60003C045 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastSwiftUpdateCheck = 0920;
+				LastUpgradeCheck = 1430;
+				ORGANIZATIONNAME = "";
+				TargetAttributes = {
+					331C80D4294CF70F00263BE5 = {
+						CreatedOnToolsVersion = 14.0;
+						TestTargetID = 33CC10EC2044A3C60003C045;
+					};
+					33CC10EC2044A3C60003C045 = {
+						CreatedOnToolsVersion = 9.2;
+						LastSwiftMigration = 1100;
+						ProvisioningStyle = Automatic;
+						SystemCapabilities = {
+							com.apple.Sandbox = {
+								enabled = 1;
+							};
+						};
+					};
+					33CC111A2044C6BA0003C045 = {
+						CreatedOnToolsVersion = 9.2;
+						ProvisioningStyle = Manual;
+					};
+				};
+			};
+			buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */;
+			compatibilityVersion = "Xcode 9.3";
+			developmentRegion = en;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = 33CC10E42044A3C60003C045;
+			productRefGroup = 33CC10EE2044A3C60003C045 /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				33CC10EC2044A3C60003C045 /* Runner */,
+				331C80D4294CF70F00263BE5 /* RunnerTests */,
+				33CC111A2044C6BA0003C045 /* Flutter Assemble */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		331C80D3294CF70F00263BE5 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		33CC10EB2044A3C60003C045 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,
+				33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+		3399D490228B24CF009A79C7 /* ShellScript */ = {
+			isa = PBXShellScriptBuildPhase;
+			alwaysOutOfDate = 1;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputFileListPaths = (
+			);
+			inputPaths = (
+			);
+			outputFileListPaths = (
+			);
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n";
+		};
+		33CC111E2044C6BF0003C045 /* ShellScript */ = {
+			isa = PBXShellScriptBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			inputFileListPaths = (
+				Flutter/ephemeral/FlutterInputs.xcfilelist,
+			);
+			inputPaths = (
+				Flutter/ephemeral/tripwire,
+			);
+			outputFileListPaths = (
+				Flutter/ephemeral/FlutterOutputs.xcfilelist,
+			);
+			outputPaths = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+			shellPath = /bin/sh;
+			shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
+		};
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		331C80D1294CF70F00263BE5 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		33CC10E92044A3C60003C045 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */,
+				33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */,
+				335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+		331C80DA294CF71000263BE5 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 33CC10EC2044A3C60003C045 /* Runner */;
+			targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */;
+		};
+		33CC11202044C79F0003C045 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */;
+			targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */;
+		};
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+		33CC10F42044A3C60003C045 /* MainMenu.xib */ = {
+			isa = PBXVariantGroup;
+			children = (
+				33CC10F52044A3C60003C045 /* Base */,
+			);
+			name = MainMenu.xib;
+			path = Runner;
+			sourceTree = "<group>";
+		};
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+		331C80DB294CF71000263BE5 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUNDLE_LOADER = "$(TEST_HOST)";
+				CURRENT_PROJECT_VERSION = 1;
+				GENERATE_INFOPLIST_FILE = YES;
+				MARKETING_VERSION = 1.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.app.RunnerTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_VERSION = 5.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/app";
+			};
+			name = Debug;
+		};
+		331C80DC294CF71000263BE5 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUNDLE_LOADER = "$(TEST_HOST)";
+				CURRENT_PROJECT_VERSION = 1;
+				GENERATE_INFOPLIST_FILE = YES;
+				MARKETING_VERSION = 1.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.app.RunnerTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_VERSION = 5.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/app";
+			};
+			name = Release;
+		};
+		331C80DD294CF71000263BE5 /* Profile */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				BUNDLE_LOADER = "$(TEST_HOST)";
+				CURRENT_PROJECT_VERSION = 1;
+				GENERATE_INFOPLIST_FILE = YES;
+				MARKETING_VERSION = 1.0;
+				PRODUCT_BUNDLE_IDENTIFIER = com.example.app.RunnerTests;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_VERSION = 5.0;
+				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/app.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/app";
+			};
+			name = Profile;
+		};
+		338D0CE9231458BD00FA5F75 /* Profile */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CODE_SIGN_IDENTITY = "-";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.14;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = macosx;
+				SWIFT_COMPILATION_MODE = wholemodule;
+				SWIFT_OPTIMIZATION_LEVEL = "-O";
+			};
+			name = Profile;
+		};
+		338D0CEA231458BD00FA5F75 /* Profile */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CLANG_ENABLE_MODULES = YES;
+				CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
+				CODE_SIGN_STYLE = Automatic;
+				COMBINE_HIDPI_IMAGES = YES;
+				INFOPLIST_FILE = Runner/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/../Frameworks",
+				);
+				PROVISIONING_PROFILE_SPECIFIER = "";
+				SWIFT_VERSION = 5.0;
+			};
+			name = Profile;
+		};
+		338D0CEB231458BD00FA5F75 /* Profile */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_STYLE = Manual;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Profile;
+		};
+		33CC10F92044A3C60003C045 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CODE_SIGN_IDENTITY = "-";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.14;
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = macosx;
+				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+			};
+			name = Debug;
+		};
+		33CC10FA2044A3C60003C045 /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CODE_SIGN_IDENTITY = "-";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				MACOSX_DEPLOYMENT_TARGET = 10.14;
+				MTL_ENABLE_DEBUG_INFO = NO;
+				SDKROOT = macosx;
+				SWIFT_COMPILATION_MODE = wholemodule;
+				SWIFT_OPTIMIZATION_LEVEL = "-O";
+			};
+			name = Release;
+		};
+		33CC10FC2044A3C60003C045 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CLANG_ENABLE_MODULES = YES;
+				CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
+				CODE_SIGN_STYLE = Automatic;
+				COMBINE_HIDPI_IMAGES = YES;
+				INFOPLIST_FILE = Runner/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/../Frameworks",
+				);
+				PROVISIONING_PROFILE_SPECIFIER = "";
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+				SWIFT_VERSION = 5.0;
+			};
+			name = Debug;
+		};
+		33CC10FD2044A3C60003C045 /* Release */ = {
+			isa = XCBuildConfiguration;
+			baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CLANG_ENABLE_MODULES = YES;
+				CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
+				CODE_SIGN_STYLE = Automatic;
+				COMBINE_HIDPI_IMAGES = YES;
+				INFOPLIST_FILE = Runner/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/../Frameworks",
+				);
+				PROVISIONING_PROFILE_SPECIFIER = "";
+				SWIFT_VERSION = 5.0;
+			};
+			name = Release;
+		};
+		33CC111C2044C6BA0003C045 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_STYLE = Manual;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Debug;
+		};
+		33CC111D2044C6BA0003C045 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				CODE_SIGN_STYLE = Automatic;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				331C80DB294CF71000263BE5 /* Debug */,
+				331C80DC294CF71000263BE5 /* Release */,
+				331C80DD294CF71000263BE5 /* Profile */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				33CC10F92044A3C60003C045 /* Debug */,
+				33CC10FA2044A3C60003C045 /* Release */,
+				338D0CE9231458BD00FA5F75 /* Profile */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				33CC10FC2044A3C60003C045 /* Debug */,
+				33CC10FD2044A3C60003C045 /* Release */,
+				338D0CEA231458BD00FA5F75 /* Profile */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				33CC111C2044C6BA0003C045 /* Debug */,
+				33CC111D2044C6BA0003C045 /* Release */,
+				338D0CEB231458BD00FA5F75 /* Profile */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 33CC10E52044A3C60003C045 /* Project object */;
+}
diff --git a/frontend/app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/frontend/app/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>IDEDidComputeMac32BitWarning</key>
+	<true/>
+</dict>
+</plist>
diff --git a/frontend/app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/frontend/app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
new file mode 100644
index 0000000..2b285b4
--- /dev/null
+++ b/frontend/app/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   LastUpgradeVersion = "1430"
+   version = "1.3">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "33CC10EC2044A3C60003C045"
+               BuildableName = "app.app"
+               BlueprintName = "Runner"
+               ReferencedContainer = "container:Runner.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      shouldUseLaunchSchemeArgsEnv = "YES">
+      <MacroExpansion>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "33CC10EC2044A3C60003C045"
+            BuildableName = "app.app"
+            BlueprintName = "Runner"
+            ReferencedContainer = "container:Runner.xcodeproj">
+         </BuildableReference>
+      </MacroExpansion>
+      <Testables>
+         <TestableReference
+            skipped = "NO"
+            parallelizable = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "331C80D4294CF70F00263BE5"
+               BuildableName = "RunnerTests.xctest"
+               BlueprintName = "RunnerTests"
+               ReferencedContainer = "container:Runner.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
+      </Testables>
+   </TestAction>
+   <LaunchAction
+      buildConfiguration = "Debug"
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      ignoresPersistentStateOnLaunch = "NO"
+      debugDocumentVersioning = "YES"
+      debugServiceExtension = "internal"
+      allowLocationSimulation = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "33CC10EC2044A3C60003C045"
+            BuildableName = "app.app"
+            BlueprintName = "Runner"
+            ReferencedContainer = "container:Runner.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </LaunchAction>
+   <ProfileAction
+      buildConfiguration = "Profile"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      debugDocumentVersioning = "YES">
+      <BuildableProductRunnable
+         runnableDebuggingMode = "0">
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "33CC10EC2044A3C60003C045"
+            BuildableName = "app.app"
+            BlueprintName = "Runner"
+            ReferencedContainer = "container:Runner.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
diff --git a/frontend/app/macos/Runner.xcworkspace/contents.xcworkspacedata b/frontend/app/macos/Runner.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..1d526a1
--- /dev/null
+++ b/frontend/app/macos/Runner.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "group:Runner.xcodeproj">
+   </FileRef>
+</Workspace>
diff --git a/frontend/app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/frontend/app/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>IDEDidComputeMac32BitWarning</key>
+	<true/>
+</dict>
+</plist>
diff --git a/frontend/app/macos/Runner/AppDelegate.swift b/frontend/app/macos/Runner/AppDelegate.swift
new file mode 100644
index 0000000..d53ef64
--- /dev/null
+++ b/frontend/app/macos/Runner/AppDelegate.swift
@@ -0,0 +1,9 @@
+import Cocoa
+import FlutterMacOS
+
+@NSApplicationMain
+class AppDelegate: FlutterAppDelegate {
+  override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
+    return true
+  }
+}
diff --git a/frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..a2ec33f
--- /dev/null
+++ b/frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,68 @@
+{
+  "images" : [
+    {
+      "size" : "16x16",
+      "idiom" : "mac",
+      "filename" : "app_icon_16.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "16x16",
+      "idiom" : "mac",
+      "filename" : "app_icon_32.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "32x32",
+      "idiom" : "mac",
+      "filename" : "app_icon_32.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "32x32",
+      "idiom" : "mac",
+      "filename" : "app_icon_64.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "128x128",
+      "idiom" : "mac",
+      "filename" : "app_icon_128.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "128x128",
+      "idiom" : "mac",
+      "filename" : "app_icon_256.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "256x256",
+      "idiom" : "mac",
+      "filename" : "app_icon_256.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "256x256",
+      "idiom" : "mac",
+      "filename" : "app_icon_512.png",
+      "scale" : "2x"
+    },
+    {
+      "size" : "512x512",
+      "idiom" : "mac",
+      "filename" : "app_icon_512.png",
+      "scale" : "1x"
+    },
+    {
+      "size" : "512x512",
+      "idiom" : "mac",
+      "filename" : "app_icon_1024.png",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
diff --git a/frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
new file mode 100644
index 0000000000000000000000000000000000000000..82b6f9d9a33e198f5747104729e1fcef999772a5
GIT binary patch
literal 102994
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
Pe7HEdAEg|=c=LY&YVNkY

literal 0
HcmV?d00001

diff --git a/frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
new file mode 100644
index 0000000000000000000000000000000000000000..13b35eba55c6dabc3aac36f33d859266c18fa0d0
GIT binary patch
literal 5680
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

literal 0
HcmV?d00001

diff --git a/frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
new file mode 100644
index 0000000000000000000000000000000000000000..0a3f5fa40fb3d1e0710331a48de5d256da3f275d
GIT binary patch
literal 520
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|Tv8)E(|mmy
zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uuz(rC1}QWNE&K#jR^;j87-Auq
zoUlN^K<V}W|Nr-^PFT-<B<I8<k2moS-$dQqjwO2}38)2pwoy<M({V6lSaDit{<(Sw
zPXRaPYYNUY7O1^kFoWZ1&9ATX7d}2E-*#lOy=2(EzuoIt*085BSnql>{r-Q+XN;zI
ze|?*NFmgt#V#GwrSWaz^2G&@SBmck6ZcIFMww~vE<1E?M2#KUn1CzsB6D2<IW)xrk
zTF<k-{!d~7Q&wNdv9*#ZTy2c$asSgRzRIqUe32s`sn+(h{GXA{&u{&Xv->+0SuRV@
zV2kK5HvIGB{HX-hQzs0*AB%5$9RJ@a;)Ahq#p$GSP91^&hi#6sg*;a~dt}4AclK>h
z_3MoPRQ{i;==;*1S-mY<(JFzhAxMI&<61&m$J0NDHdJ3tYx~j0%M-u<zsp4Sq6Wua
z5BBhjsWTfpZEpHBEIjPnnRxiIKToJ|*&=PntIR&BpDzYU*}YSmk@;dK=M)=9O`bU(
o30)I1CTw2MWPDjr#qiV&hQFoXIy#f5hk;_j)78&qol`;+052KE`v3p{

literal 0
HcmV?d00001

diff --git a/frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
new file mode 100644
index 0000000000000000000000000000000000000000..bdb57226d5f2bd20f11934f4903f16459cf52379
GIT binary patch
literal 14142
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
K%C(A?AO9DJ-0fok

literal 0
HcmV?d00001

diff --git a/frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
new file mode 100644
index 0000000000000000000000000000000000000000..f083318e09ca1b6b8484b1694a149f0c5d5cac1d
GIT binary patch
literal 1066
zcmV+_1l9YAP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F800001b5ch_0Itp)
z=>Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@
z1ONa40RR91AfN*P1ONa40RR91AOHXW0IY^$^8f$?lu1NER9Fe^SItioK@|V(ZWmgL
zZT;XwPgVuWM>O%^|Dc$VK;n&?9!&g5)aVsG8cjs5UbtxVVnQNOV~7Mrg3+jnU;rhE
z6fhW6P)R>_eXrXo-RW*y6RQ_qc<j#1d-MCvdv9j8z=r(i2q<p&rfD9eu@2G*X@FEG
z6~cb9uStEZLK5`yo%9{)UDA7sqGXR#mxB;+fV7|VZ_5LkFz5hj?;@j8fQ!XEq!(M{
zYz-RZu=m?3<!>b^s1wTu$TwriZ`=JUws>vRi}5x}MW1MR#7p|gIWJlaLK;~xaN}b<
z<-@=RX-%1mt`^O0o^~2=CD7pJ<<$Rp-oUL-7PuG>do^5W_Mk#unlP}6I@6NPxY`Q}
zuXJF}!0l)vwPNAW;@5DjPRj?*rZx<jK$)1#?a4VGrm!=3lJYK6-%z3AD1isd9rK<&
zotoW{3D^d+4f&nH7`%5jZrktykBXBK9scZ-LUvwn+Zf6O*3BH=2BOx=IRz|CDC|>l
zwn;A(cFV!xe^CUu+6SrN?xe#mz?&%N9QHf~=KyK%DoB8HKC)=w=3E?1Bqj9RMJs3U
z5am3Uv`@+{jgqO^f}Lx_Jp~CoP3N4AMZr~4&d)T`R?`(M{W5WWJV^z~2B|-oih@h^
zD#DuzGbl(P5>()u*YGo*Och=oRr~3P1wOlKqI)udc$|)(bacG5>~p(y>?{JD7nQf_
z*`T^YL06-O>T(s$bi5v~_fWMfnE7Vn%2*tqV|?~m;wSJEVGkNMD>+xCu#um(7}0so
zSEu7?_=Q64Q5D+fz~T=Rr=G_!L*P|(-iOK*@X8r{-?oBlnxMNNgCVCN9Y~ocu+?XA
zjjovJ9F1W$Nf!{AEv%W~8oahwM}4Ruc+SLs>_I_*uBxdcn1gQ^2F8a*vGjgAXYyh?
zWCE@c5R=tbD(F4nL9<VTK~ebn>NS?$PN1V_2*WR?gjv3)4MQeizuH`;sqrhgykEzj
z593&TGlm3h`sIXy_U<7(dpRXGgp0TB{>s?}D{fwLe>IV~exweOfH!qM@CV5kib!YA
z6O0gvJi_0J8IdEvyP#;PtqP*=;$iI2t(xG2YI-e!)~kaUn~b{6<BmbAI7C`%X>(&n
zp)?iJ`z2)Xh%sCV@BkU`XL%_|FnCA?cVv@h*-FOZhY5erbG<m)%ac-@w;CT4TyWxt
kNncSvOvqtF{%Hh$1H=*W-r{pWaR2}S07*qoM6N<$g8Wt7Y5)KL

literal 0
HcmV?d00001

diff --git a/frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
new file mode 100644
index 0000000000000000000000000000000000000000..326c0e72c9d820600887813b3b98d0dd69c5d4e8
GIT binary patch
literal 36406
zcmeGE=RaKU_dbB`8KZ_EB%(x35TbX25d=Z>h)%Q!Av#fJM3Csc_g<nz^d3ZyUZRH>
zC2I6x%$)80`Tkz#KRA!h1FzY`?0es3t!rKDT5EjPe6B=BLPr7s0GW!if;Ip^!AmGW
zL;$`Vdre+|FA!I4r6)keFvAx3M#1`}ijBHDzy)3t0gw<o0CxQm@P`ik0RX&g2!IE^
zLau+84gG(Ag#y`l|KIED58gPh4FUi-prRnB>jl|qC2YB`SSxFKHr(oY#H$)x{L$LL
zBdLKTlsOrmb>T0wd=&6l3+_Te>1!j0OU8%b%N<Ko#ZEw**BmZNWchQD`41c-9hRid
zup{-h!wadIdzsILCKiu&M>342^opKmT)gni(wV($s(>V-fUv@0p8!f`=>PxC|9=nu
ze{ToBBj8b<{PLfXV$h8YPgA~E!_sF9bl;QOF{o6t&JdsX?}rW!_&d`#wlB6T_h;Xf
zl{4Tz5>qjF4kZgjO7ZiLPRz_~U@k5%?=30+nxEh9?s78gZ07YH<f(VdP2w|K;`V+a
zSU&!%=C5aS?5~xgm4;ps#|80kHb3cl6$$KTD%`Eg#!o(BY!;i`Z|-i6<^8-k+1B&m
z_%cA#qPLW(mG?9yf?n*y^RDd$E+-Dts?FINJE~QYWto3cC@Qf*{V3h8XrfQcRq<WU
z1&^W^W0?MF?{|F&3ZAWqX~-d?7tId$5HFoksq}@Nv3$QblByo!R$KMeviGK{G+oKa
z%2b)Y{riya!a%c3bq@cjQoROuuh*G>B`FV`4%hlQlMJe@J`+e(qzy+h(9yY^ckv_*
zb_E6o4p)ZaWfraIoB2)U7_@l(J0O%jm+Or>8}zSSTk<a4@uWZ_pD$@B@k*Ipd`2=s
zhXdDW`VT7PvXx{Qq|dWAdkL6Q<ZnvkpN-0s?<SFNcr~&QD*3u<X{Yr&4QiLv6!`Yl
zQ7X3P`5xC%<g*VtseTSbXwNYBez+AN%EG)qo84j-)@{PRC)n@N*b>M$ASG^w3F|I?
z$+eHt7T~04(_WfKh27zq<M+F8%cr0AY~kW1b?@zX9d|y&9!N9_^qCjbDBrIc>S$6*
zzyy-ZyqvSIZ0!kkSvHknm_P*{5TKLQs8S6M=ONuKAUJWtpxbL#2(_huvY(v~Y%%#~
zYgsq$JbLLprKkV)32`liIT$KKEqs$iYxjFlHiRNvBhxbDg*3@Qefw4UM$>i${R5uB
zhvTgmqQsKA{vrKN;TSJU2<s?{=#%q717?q=>$f9q=y{$oH{<)woSeV>fkIz6D8@KB
zf4M%v%f5U2?<8B(xn}xV+gWP?t&oiapJhJbfa;agtz-YM7=hrSuxl8lAc3GgFna#7
zNjX7;`d?oD`#AK+fQ=ZXqfIZFEk{ApzjJF0=yO~Yj{7oQfXl+6v!wNnoqwEvrs81a
zGC?yXeSD2NV!ejp{LdZGEtd1T<NHg;^UK)N2gejhi4fB9j}5IYuYnqx{rpCWlLs%n
z$!(@_+wItG>J)3g{P6j#2jLR`cpo;YX}~_gU&Gd<+~SUJVh+$7S%`zLy^QqndN<_9
zrLwnXrLvW+ew9zX2)5qw7)zIYawgMrh`{_|(nx%u-ur1B7YcL<U>p&WFa24gAuw~&
zKJD3~^`Vp_SR$WGGBaMnttT)#fCc^+P$@UHIyBu+TRJWbcw4`CYL@SVGh!X&y%!x~
zaO*m-bTadEcEL6V6*{>irB8qT5Tqd<B(D{NFY@~;PY}S~gcg!{3xur`iJ!1c*Tgtq
zEiqkfD#ckD;|61Qj@MOG<gP<g-%aS@y~_{>54TC4`h`PV<p;~ci}{~|;ZI9H6Tn5e
zI!g$5*KxBW{&j&vzuR>cd^AM6^Qf=GS->x%N70SY-u?qr>o2*OV7LQ=j)pQGv%4~z
zz?X;qv*l$QSNjOuQZ>&WZs2^@G^Qas`T8iM{b19dS>DaXX~=jd4B2u`P;B}JjRBi#
z_a@&Z5ev1-VphmKlZEZZd2-Lsw!+1S60YwW6@>+NQ=E5PZ+OUEXjgUaXL-E0fo(E*
zsjQ{s>n33o#VZm0e%H{`KJi@2ghl8g>a~`?mFj<s<bobqX#|}4Uu~P=nu)}_`#<bf
z7N$OVgP1l+$_o^sZr^EL_B>w+$zlt|VJhSU@Y%0TWs>cnD&61fW4e0vFS<JbKF5ve
zKk*kP58WfJHlG5a%d<&l&!@RFyjDM7?zdg;X{dVQq!vE5a9rQ(#saO3YgHefwTzPP
zacI9fC0{Mx<;e7c4rGx{-jOARHMj#aRf=VZkb53?qfaohi90frO^^Ch{@WsZm}#sl
z;mx-5)iASI7RV6Us43v?YSQq9c!Uu-J^3jQ^YsgPx&JK1A7qB-651(ts;#^~()jar
zhzWw5=ROL+cFPgon`EQUlI9|$_$rniG-YUCP{$wTXt`@X@B&e<Cp8Fe4Say8rN#v{
zAkW*hnd`knrc67_C3Onqhj3H3AH{{#x^+`3IS9G`o%Fs{XZGG8nhG3WA={n;?$nV&
z$msQ32gIR^OD5d8(mew6E|CHyBmrC!{ughSEe`X{?CP&R&bsp>aXZa4-c}U{4QR8U
z;GV3^@(?Dk5uc@RT|+5C8-24->1snH6-?(nwXSnPcLn#X_}y3XS)MI_?zQ$ZAuyg+
z-pjqsw}|hg{$~f0FzmmbZzFC0He_*Vx|_uLc!Ffeb8#+@m#Z^AYcWcZF(^Os8&Z4g
zG)y{$_pgrv#=_rV^D|Y<_b@ICleUv>c<0HzJDOsgJb#Rd-Vt@+EBDPyq7dUM9O{Yp
zuGUrO?ma2wpuJuwl1M=*+tb|qx7Doj?!F-3Z>Dq_ihFP=d@_JO;vF{iu-6MWYn#=2
zRX6W=`Q`q-+q@Db|6_a1#8B|#%hskH82lS|9`im0UOJn?N#S;Y0$%xZw3*jR(1h5s
z?-7D1tnIafviko>q6$UyqVDq1o@cwyCb*})l~x<@s$5D6N=-Uo1yc49p)xMzxwnuZ
zHt!(hu-Ek;Fv4MyNTgbW%rPF*dB=;@r3YnrlFV{#-*gKS_qA(G-~TAlZ@Ti~Yxw;k
za1EYyX_Up|`rpbZ0&Iv#$;eC|c0r4XGaQ-1mw@M_4p3vKIIpKs49a8Ns#ni)G314Z
z8<zhMC&uyKbr!0p$@ulq+M0{sArrl_R_Y^t*2#kW{j8)GlY_CI?GFb57b_`FZ26xl
zDr7GbeWE<5^K3iH@I#z;F)?DnQ|q5bd?Lw){3h4VIK*Mk+S|MC7&)vA3IEgRynAgT
z0Ock%^c9TZm<jifY0%obgUJpiT!~KyEZr?RoGJIKpL1;9&7{&MJA3{^^Z#z(g!=jU
zh2SpRahGu#(kGM4*6zq*{NMHSc`sfA!XI+UL%($``z&8B{qxyx6^oahL5scmL2-RE
ze4T=V?Kj^3`<dpw7*nKvgTiS0dvW3_#<bMKBy;l#&pwtA^EzC^d%-0zs$JiZNEwYc
z%ZM3IY7?eCs#kbE<$e({QoZ>$E<zeO(fqU0QF)eZ8M$>i?AhiT5dQGWUYdCS|IC7r
z=-8ol>V?u!n%F*J^^<H2=4hm>PZ(ONT&$Ph;r6X;pj|03HlDY6r~0g~X<Vn7mLf6Z
zKSZ#FS=D#k8<E`pk~L_+^OBLsPYLCu$LRxbnQzLEaT}?g`t91A&HIDY43iK<)e0If
zh?>#zuzVU%a&!fs_f|m?qYvg^Z{y?9Qh7Rn?T*F%7lUtA6U&={HzhYEzA`knx1VH>
z{tqv?p@I(&ObD5L4|YJV$QM>Nh-X3cx{I&!$FoPC_2iIEJfPk-$;4wz>adRu@n`_y
z_R6aN|MDHdK;+IJmyw(hMoDCFCQ(6?hCAG5&7p{y<cZYLkfEs;kgkHLo>->0Uckv#
zvooVuu04$+pqof777ftk<#42@KQ((5DPcSMQyzGOJ{e9H$a9<2Qi_oHjl{#=FUL9d
z+~0^2`tcvmp0hENwfHR`Ce|<1S@p;MNGInXCtHnrDPXCKmMTZQ{HVm_cZ>@?Wa6}O
zHsJc7wE)mc@1OR2DWY%ZIPK1J2p6XDO$ar`$RXkbW}=@rFZ(t85AS>>U0!yt9f49^
zA9@pc0P#k;>+o5bJfx0t)Lq#v4`OcQn~av__dZ-RYOYu}F#pdsl31C^+Q<?6KFjka
zqP|_xm2{9&`X+(|M`1v-@%gq{)79n3<D(&suiNeRnVxszuMg=rbJd?nsii6~be$2%
znOMWz=0A$*R^(x<C6u#<h%$t&2dL|?XgTKVeR89Pjvu69>gro}$q~5A<*c|kypzd}
ziYGZ~?}5o`S5lw^B{O@laad9M_D<sU@Nn20B8N8gdV8{r-}`nLoW^5O6E1cFOd8_A
zX<lCNwH}XWST!%JzR`e6|Ichj^@x=D;JCD9%=&E?^HC-&W<!=-@5ZvoJiezYIdbuW
zPo*HqW6^!asOhhYt;PTOIwU~Avd33`nB*=WAwiDZ7c#{uTC!tBlFd7KfO{~>uJle-
z*9C7o=CJh#QL=V^sFlJ0c?BaB#4bV^T(DS6&Ne&DBM_3E$S^S13<joH2iW(oIIn$T
zo&TJVB&4HQD{nZu>qC$7_Z?GYXTpR@wqr70wu$7+qvf-SEUa5mdHvFbu^7ew!Z1a^
zo}xKOuT*gtGws-a{Tx}{#(>G~Y_h&5P@Q8&p!{*s37^QX_Ibx<6XU*AtDOIvk|^{~
zPlS}&DM5$Ffyu-T&0|KS;Wnaqw{9DB&B3}vcO1<R|0l`O|J&fuQ22fTAtUEJ6k{R@
z$(&?FKB*+)bRmbEY%|$QTQ~N4EBd(@@LpR8K&c$uk*^Zhrq7$S+mD?4q}C&zR}$s`
z050V%u|rrUq4&p|c|wNd)c+6O!;xQZ((_6GxKyzm6NO4X(%Y`yC&0_rpY}Sv=egh<
zQh)QQ%YSr*B7l{-YPW9Q-;@+`7dSNrcC~n)P}*B_mO`?55b>4wn;)O_e@2*9B&0I_
zZz{}CMxx`hv-XouY>^$Y@J(_INeM>lIQI@I>dBAqq1)}?Xmx(qRuX^i4IV%=MF306
z9g)i*79pP%_7Ex?m6ag-4Tlm=Z;?DQDyC-NpUIb#_^~V_tsL<~5<&;Gf2N+p?(msn
zzUD<r{_O#w*E4WUinF~M^J>~g>OoW@O}y0@Z;RN)wjam`CipmT&O7a|YljZqU=U86
zedayEdY)2F#BJ6xvmW8K&ffdS*0!%N<%RB!2~PAT4AD*$W7yzHbX#Eja9%3aD+Ah2
zf#T;XJW-GMxpE=d4Y>}jE=#U<nDc*G<M1ZXw!7ucHS3fb^$f9Re2Z4WmR$8-61^I?
zRlEtUsG1s5S#A}}A}jT&WAD`%^!vVwk`XH1yiwZ<^ub>`IqgSoWcuvgaWQ9j1CKzG
zDkoMDDT)B;Byl3R2PtC`ip=yGybfzmVNEx{xi_1|Cbqj>=FxQc{g`xj6fIfy`D8fA
z##!-H_e6o0>6Su&$H2kQTujtbtyNFeKc}2=|4IfLTnye#@$Au7Kv4)dnA;-fz@D_8
z)>ir<E}8DFE5kwq0cz~qqu?R3qwVIa+K<F;8P%WGo{p78|J)}DbuIcFYs*va|M?B%
zr?gN{(vVV7{7?gyb6jLYHFT3mEt!8MU*FVQkqnu;^^7o@_0BW1<|Xve##zKYsnhsP
zy^(8H4_xoN^$_mnOmcg~&3H?xsf6`{3ZAferu>G$)dk<qHN7N)p%Z<Y6+|F0!d9go
zm)zFZh!(O|bAVYr{GA9g+*NT4b3VfGpL}7&VQ+wJ;{p&(<EZj)aoA9L4Jg2>BY~zX
zC!ZXLy*L3xr6cb70QqfN#Q>lFIc<>}>la4@3%7#>a1$PU&O^&VszpxLC%*!m-cO{B
z-Y}<!@c6mS8LYF?0vAo+cNY=3tIM0Rn1jH1Vs<dOQ<MV+aJ;lf?d~h)oTw~aTBRRk
z=pZynNRC}%z33X-5ee}?8v9l<VvQm7^YHmcqU%u1w7b1M@fkUq6jYj@t1cvm`aRR^
ze{~W22qn&9aU~={xhV<Du6OkJ?;A2%m0sT`P-y?ea*`qCy>rQr4$84(hvy#R69H{H
zJ*O#uJh)TF6fbXy;fZkk%X=CjsTK}o5N1a`d7kgYYZLPxsHx%9*_XN8VWXEkVJZ%A
z1A+5(B;0^{T4aPYr8%i@i32h)_)|q?9vws)r+=5u)1YNftF5mknwfd*%jXA2TeP}Z
zQ!m?xJ3?9Lp<x&0=u@b0$<!m2CF8{0yMW=tcUpzx#2o2W>PM?_A3$hQ1QxNbR&}^m
z!F999s?p^ak#C4NM_x2p9FoXWJ$>r?lJ)2bG)sX{gExgLA2s5RwHV!h6!C~d_H||J
z>9{E{mEv{Z1z~65Vix@dqM4ZqiU|!)e<w>WX$mwS5mLSufxbpBqqS!jShq1bmwCR6
z4u<o~Z&JF}ZU?h}NssYn2~f(#%NIbem^`z2lyngk)RyN~9kYP@9$ihevPrXVxLf?`
zs}SFKUtF8x@Oiu2?7?ySuPA&f4=U*Ed{f*)bR*#+)@4QU(5^x9-yR}cPnzaIMw-Ut
zCBHZR*e{omeyLAMw(p~0Qc*F9INiO2jnDc|@dV<HGl*VS!upD9#=5z*$&qwGK?1ja
zqSaxKPp+KY8`e=jqWFS&oTR}<RDu6{?@gYFLpMFN&(k_i{)opDzbRinzGBt;JbH-3
zsBz)oLxOY<3Gvh^#<KZ#O_7PRPs)SyhzO8vHt#Y>Bri7ezMeS6ycaXPVu(i2up$L;
zjpMtB`k~WaNrdgM_R=e#SN?Oa*u%nQy01?()h4A(jyfeNfx;5o+kX?maO4#1A^L}0
zYNyIh@QVXIFiS0*tE<Ql)bx4D`dDA~n9jCX(2(U{r)q4_yGL1<uVxoovd4GHNtCt*
zjXu&m>}2SWTrWNP3pH}1Vz1;E{@JbbgDFM-_Mky^7gH}LEhl~Ve5Pexgb<VvJYMUr
zI**#w1>IyZ(IN%PqcaV@*_`ZFb=`EjspSz%5m2E34BVT)d=<xZ79`HuR4ffVr^|O0
za#-<8Zs{BqrlPd&x*akz`SpS8z@A_FfqnpgJ+8n4%`$7qcu}o+1cZ*OM|x7VFR7=A
zo<!1%Ilger5+->LGyHVz@-e%9Ova*{5@RD;7=Ebkc2GP%pIP^P7KzKapnh`UpH?@h
z$RBpD*{b?vhohOKf-JG3?A|AX|2pQ?(>dwIbWhZ38GbTm4AImRNdv_&<99ySX;kJ|
zo|5YgbHZC#HYgjBZrvGAT4NZYbp}qkVSa;C-LGsR26Co+i_HM&{awuO9l)Ml{G8zD
zs$M8R`r+>PT#Rg!J(K6T4xHq7+tscU(}N$HY;Yz*cUObX7J7h0#u)S7b~t^Oj}TBF
zuzsugnst;F#^1jm>22*AC$heublWtaQyM6RuaquFd8V#hJ60Z3j7@bAs&?dD#<ivf
z(|aoRr|<kR3-jfm1IytP+tngT4h_ZE(IWc<$UA*nSeJ>*>H0SJaDwp%U~27>zdtn+
z|8sZzklZy$%S|+^ie&P6++>zbrq&?+{Yy11Y>@_ce@vU4ZulS@6yziG6;iu3Iu`M=
zf3rcWG<+3F`K|*(`0mE<$89F@jSq;j=W#E>(R}2drCB7D*0-|D;S;(;TwzIJkGs|q
z2qH{m_zZ+el`b;Bv-#bQ>}*VPYC|7`rgBFf2oivXS^>v<&HHTypvd4|-zn|=h=TG{
z05TH2+{T%EnADO>3i<U+^h<TPR(jL@J|Q(zyU|~$GOEs|fJ0fsx-;v+WoUu9X^Js6
z`1|+ooty|=4K2yigUD00%*TyNr*D_?%t!8p$-`LLkOGJr%*Mx^(-~6Te|d!PD>|CB
zCu60#q<L<EUO}HHFsUf~l+-cdL5-us)u5`aKjJHuw84s>k`}GW{n4l-E$VrqgZGbI
zbQW690KgZt4U3F^5@bdO1!xu~p@7Y~*_FfWg2CdvED5P5#w#V46LH`<&V0{t&Ml~4
zHNi7lIa+#i+^Z6EnxO7KJQw)wD)4~&S-Ki8)3=jpqxmx6c&zU&<&h%*c$I(5{1HZT
zc9WE}ijcWJiVa^Q^xC|WX0habl89qycOyeViIbi(LFsEY_8a|+X^+%Qv+W4vzj>`y
zpuRnjc-eHNkvXvI_f{=*FX=OKQzT?bck#2*qoKTHmDe>CDb&3AngA1O)1b}QJ1Tun
z_<@yVEM>qG7664Pa@dzL@;DEh`#?yM+M|_fQS<7yv|i*pw)<s;k^3L}xk=UU5;Leh
zdg5?+WMQx&TgX?x>|Z8)9IR+QB7N3v3K(wv4OY*TXnH&X0nQB}?|h2XQeGL^q~N7N
zDFa@x0E(UyN7k<T;f{y|6<e&5Uh2gyt}Ks+R9hhfxtVbGFD<DX71gc#&f^qo-(@Uf
zxNk1j*iEoMvrFtBv2$B*wNl)Iz@?AXvSj?2_isNze}?PA(ghF(8;Je!ciWh&b9-{6
zS&Laixw)Ro#aQ8O#|_$Up+_cn8GoM;%#xjcn<&8q9&ouV3`^~|oc#J~`7e1pufmZx
z%!C@R!w$XQj>9g%IFq7Sf+EAfE#K%%#`)!90_)Dmy3Bll&e1vHQyPA<Ap4`!BeoHK
z@7Zefzc+U(9#>87TaF(xbqMpDntVp?;8*$87STop$<Q_aU<IA<1yYCB=xy!P$AxJa
zJ_nSN64}`s(^l`5{+A|3FT&Udl1qnI8h#S=MZh735G^vOYW+<9qqKF&vX)fR(67hj
zsf7@Qq@(C*+?}hdtI@Q`;jatEtU4ci8(&b)JA5PSvGt-1=wt&>!EAnGhZ?>mqPJ(X
zFsr336p3P{PpZCGn&^LP(JjnBbl_3P3Kcq+m}xVFMVr1zdCPJMDIV_ki#c=vvTwbU
z*gKtfic&{<5ozL6Vfpx>o2Tts?3fkhWnJD&^$&+Mh5WGGyO7fG@6WDE`tEe(8<;+q
z@Ld~g08XDzF8xtmpIj`#q^(Ty{Hq>t*v`pedHnuj(0%L(%sjkwp%s}wMd!a<*L~9T
z9MM@s)Km~ogxlqEhIw5(lc46gCPsSosUFsgGDr8H{mj%OzJz{N#;bQ;KkV+ZWA1(9
zu0PXzyh+C<4OBYQ0v3z~Lr;=C@qmt8===Ov2lJ1=DeLfq*#jgT{YQCuwz?j{&3o_6
zsqp2Z_q-YWJg?C6=!Or|b@(zxTlg$ng2eUQzuC<+o)k<6^9ju_Z*#x+oioZ5T8Z_L
zz9^A1h2eFS0O5muq8;LuDKwOv4A9pxmOjgb6L*i!<dl2>-(0`Ie^d5Fsgspon%X|7
zC{RRXEmYn!5zP9XjG*{pLa)!2;PJB2<-tH@R7+E1cRo=Wz_5Ko8h8bB$QU%t9#vol
zAoq?C$~~AsYC|AQQ)>>7BJ@{Cal)ZpqE=gjT+Juf!RD-;U0mbV1ED5PbvFD6M=qj1
zZ{QERT5@(&LQ~1X9xSf&@%r|3`S#ZCE=sWD`D4YQZ`MR`G&s>lN{y2+HqCfvgcw3E
z-}Kp(dfGG?V|97kAHQX+OcKCZS`Q%}HD6u*e$~Ki&Vx53&FC!x94xJd4F2l^qQeFO
z?&JdmgrdVjroKNJx64C!<b<#AliD%%@pmJ$_XjF$d?*RUy0fca@iIacvY$Vy&65#1
zeEo5!6yYG2q&QLr$u{3U%eM9Mx=RRgrp;!R7n=cRhSToBjO{K*a;t2&-#eW3R?xzn
z!-eyf-PQViLzOP(C?=SYNCyHdCm1z6<*FErknmpu(CJDuCo3XQ`8~~&c=ihh0nJ9#
zsqb<6Z{=ln17U^jCLBM>H<qukZuN~HgM35YV^^$xooNqoVxa#zH-j{vP=>&Vncr^w
zzR#X<dhd9kz3qoka{y?})GK?@Pq)s<i?=i6+HI`!1m1f+y*)nFTMw4h#tI?iho3@K
zG*kFj_U{_}6^pdQ+UaV{93+c7v-$vn+VfuR8Oy6b!p87ABmmlyyP=f#AZ}gDhfih~
z9#Ua*xtcZ`MGD_hf3ae)6$cLM=7>I}Dn&o8jB~_YlVM^+#0W(G1LZH5K^|uYT@KSR
z^Y5>^*Bc45E1({~EJB(t@4n<Grrf*>9gb-eT#s@@7)J^^<_VV`Pm!h7av8XH6^5zO
zOcQBhTGr;|MbRsgxCW69w{bl4EW#A~);L?d4*y#j8Ne=Z@fmJP0k4<!IQLN&MQa7!
zelb>{_cQ~KA|Y#_#BuUiYx8y*za3_6Y}c=GSe7(2|KAfhdzud!<Xqat^pPNyjfPEM
zxF#h&<ltr6Rs-ckY&ww}HR!%OyNI-Kbn|UvDW=V09t6I+^$YzjBUJE@Zq-abt07!o
z^)Lbhf5}_Ug^ymR4ftz^^q_RPgriysvk4x1Kx^zjf+Z?<Sa!anmw(^FwsTcf5_Isr
z_Z*AaOXC9pO~Z3Dp;D{onRB*1Ygb`2H=|ROn4!7$J1j`}+!v)gEAAba>Zq&}j)=o4
z7R|&&oX7~e@~HmyOOsCCwy`AR+deNjZ3bf6ijI_*tKP*_5JP3;0d;L_p(c>W1b%sG
zJ*$wcO$ng^aW0E(5ldckV9unU7}OB7s?Wx(761?1^&8tA5y0_(ieV>(x-e@}1`lWC
z-YH~G$D>#ud!SxK2_Iw{K%92=+{4yb-_XC>ji&j7)1ofp(OGa4jjF;Hd*`6YQL+Jf
zffg+6CPc8F@EDPN{Kn96yip;?g@)qgkPo^nVKFqY?8!=h$G$V=<>%5J&iVjwR!7H0
z$@QL|_Q<v#0qanvql2WtUW=tmoy-L%ihZi$BtWiEz%@mLDkiS!7Xj_jj62r!5T3GX
zpKBKH@o=Vr8)z9A{mXAYL7LQRU5D$}ncZFf+qC%tD+tS`hisLl8gY_X0)5@#3;ItT
zvsg(OKOuQfn#I<V5kmMh$p%Ax4XuC$wToH|U2IT)nc(`!ESBuI0J8{8VdfnXvxsn<
zK<PujQ{X;cY>81I;Bnq8-5JyNRv$Y>`sWl{qhq>u+X|)@cMlsG!{*lu?*H`Tp|!uv
z9oEPU1jU<BGX-Z%o>Ej@ueBr}%Y)7Luyi)REaJV>eQ{+uy4uh0ep0){t;OU8D*RZ&
zE-Z-&=BrWQLAD^A&qut&4{ZfhqK1ZQB0fACP)=zgx(0(o-`U62EzTkBkG@mXqbjXm
z>w`HNeQM?Is&4xq@BB(K;wv5nI6EXas)XXAkUuf}5uSrZLYxRCQPefn-1^#OCd4aO
zzF=dQ*CREEyWf@n6h7(uXLNgJIwGp#Xrsj6S<^bzQ7N0B0N{XlT;`=m9Olg<>KL}9
zlp>EKTx-h|%d1Ncqa=wnQEuE;sI<B=^sH}DI8Vwo$}+q~(BHW*ibBrim5-GCkXV}q
zipyXrc$%KeuNL|;iG-O!;*}7N&YPFzOXBhufpzwgS$_##Ruu?Yp-gysG~uSBh(@?X
z$?P2zAxGcRLlg9n?z5;DXa5ZZp@sgw-yx~sHSruax*Ii%)x`3{4qX(rFs9Zn+%|lv
z!krFzc#GKAXjh+Q;phiZ#YCj!<nvAJ^#e>O-f#%Bs?g4}&xS?$9MG?n$isHky0caj
za8W+B^ERK#&h?(x)7LLpOqApV5F>sqB`sntV%SV>Q1;ax67qs+WcssfFeF3Xk=e4^
zjR2^(%K1oBq%0%Rf!y&WT;lu2<K$BnxZ?DA9*#8~UsJH?6S-VI5{^nnOuk{0raVvp
zlL~-jS||S}?PL4UfE0Nk4P$(?6Ya3yT(Wgq<KHRYxT0O}GIN1b@c|6^R+Mk@OP)rn
z`^(5gEMnP;M`z?<2g<8Smt~+&%=#Yvyzx!iaxbftm-CvwwTN3W8aDNR5}PjInfKsE
z5Tz9{0=6Y!)@mtjsipw?K*1Rf(agU}3FHcQ&QJoBE|wlzV(Yybw&?XF^{^S6hEZJh
z9Gho}Y<{xUAOqQjoeoXV2e9%;j5I?uw}WF?fJoB!vX!Ljln~Ax`b;LlvjKM5(w09}
zGc~2>Co(rHi|r1_uW)n{<7fGc-c=ft7Z0Q<iNfGZWI#OC@@VG2KfN?Lk1Vz$-0r~v
zOYF=*GERO<0HL>}r4W$o$@tQF#i?jDBwZ8h+=SC}3?anUp3mtRVv9l#H?-UD;HjTF
zQ*>|}e=6gDrgI9p%c&4iMUkQa4zziS$bO&i#DI$Wu$7dz7-}XLk%!US^XUIFf2obO
zFCTjVEtkvYSKWB;<0C;_B{HHs<El7_s8Bm^*6YFO5tpWky-Q~VC=JPCI1hVOsDfl)
z+ddm)+Q#&f*Ra(WkH=&ZWfPLwxCvBr9s{2sns+S=??$~4cm`1f1rPE82SjTu7cPHG
zFS58I@=EC^)A9MLqB@OU+pbd5kloH{6bb#-XSf3_^c8U2M*-IwxYaC}!fyiOpT|8-
zIS6sbo+jwhva34{-kN6e++o7Zv+T=McP)R`kyvM{lTn$GfF(XMsIGQxEJ}0DOki(Q
ztyLujZbBwUvpF6@69jN9t|PJUQRHnZhMjY%&$-Ofk3n+9@s@kSe27W)s%H&tKlu#V
zC#CbBJ{KqSKoe>~ax_48^Cml*mjfBC5*7^HJZiLDir(3k&BerVIZF8zF;0q80eX8c
zPN4tc+Dc5DqEAq$Y3B3R&XPZ=AQfFMXv#!RQnGecJONe0H;+!f^<X9lvh@ZgRiE!(
zC>h5x0wS<+%;D}MpUbTNUBA}S2n&U59-_5HKr{L^jPsV8B^%NaH|tUr)mq=qCBv_-
ziZ1xUp(ZzxUYTCF@C}To;u60?RIfTGS?#JnB8S8@j`TKPkAa)$My+6ziGaBcA@){d
z91)%+v2_ba7gNecdj^8*I4#<11l!{XKl6s0zkXfJPxhP+@b+5ev{a>p*W-3*25c&}
zmCf{g9mPWVQ$?Sp*4V|lT@~>RR)9iNdN^7KT@>*MU3&v^3e?=NTbG9!h6C|9zO097
zN{Qs6Yw<Nd$b;u}H{)5dU4d$I*p5t{mCRSd<|}$eVFHSPn=BoS$eWN62dSw4m&Ar0
zo@qy`BzTM;t5B9EluUe3mIE`W<cAL;(H!Nvh5O=AL6~N;`UZ(kbfoNUYG!>R-5$)~
z`b~qs`a1Dbx8P>%V=1XGjBptMf%P~sl1qbHVm1HYpY|-Z^Dar8^HqjIw}xaeRlsYa
zJ_@Apy-??`gxPmb`m`0`z`#G7*_C}qiSZe~l2z65tE~IwMw$1|-u&t|z-8SxliH00
zlh1#kuqB56s+E&PWQ7Nz17?c}pN+A@-c^xLqh(j;mS|?>(Pf7(<e4L1ie`y##T7bp
z`?p37h!GR?*#|T1xJsUZ7A^%^_&h~6WK^^`MGK?~^*9EJseOytwO)-zbdXYlG>?qd
z5q@jkc^nA&!K-}-1P=Ry0yyze0W!+h^iW}7jzC1{?|rEFFWbE^Yu7Y}t?jmP-D$f+
zmqFT7nTl0HL|<j7tfRrHM-K+2Y!-<QDHj|^5e2ZSL-Qfgd4y59J@P>4jwGm7w@a>9
zKD)V~+g~ysmei$OT5}%$&LK<VtESlV;rVc`lsNBFGltD%b`GL<x6Ge&g}%B4slim<
zMmg>8?ib|8aY|>W3;P+0B;=oD=?1rg+PxKcP(d;OEzq1CKA&y#boc51P^ZJPPS)z5
zAZ)dd2$glGQXFj$`XBBJyl2y-aoBA8121JC9&~|_nY>nkmW>TLi%mWdn-^Jks-Jv|
zSR*wij;A3Fcy8KsDjQ15<r6O~x~pb~X5yj3_K>?Z9oOj|Qw2;jgJiq>dxG(2I2RE-
z$As!#zSFIskebqU2bnoM^N<4VWD2#>!;saPSsY8OaCCQqkCMdje$C?Sp%V}f2~tG5
z0whMYk6tcaABwu*x)ak@n4sMElGPX1_lmv@bgdI2jPdD|2-<~Jf`L`@>Lj7{<-uLQ
zE3S_#3e10q-ra=vaDQ42QUY^@edh>tnTtpBiiDVUk5+Po@%RmuTntOlE2<Z{e%2*S
zr>9I4MeJI?;`7;{3e4Qst#i-RH6s;>e(Sc+ubF2_gwf5Qi%P!aa89fx6^{~A*&B4Q
zKTF|Kx^NkiWx=RDhe<{PWXMQ;2)=SC=yZC&mh?T&CvFVz?5cW~ritRjG2?I0Av_cI
z)=s!@MXpXbarYm>Kj0wOxl=eFMgSMc?62U#2gM^li@wKPK9^;;0_h7B>F>0>I3P`{
zr^ygPYp~WVm<rnkTV&vfb;fqH*!2%tp=gl*L+Z8@>?Qbp6O3*O2)(`y)x>%ZXtztz
zMAcwKDr=TCMY!S-MJ8|2MJCVNUBI0BkJV6?(!~W!_dC{TS=eh}t#X+2D>Kp&)ZN~q
zvg!ogxUXu^y(P*;Q+y_rDoGeSCYxkaGPldDDx)k;ocJvvGO#1YKoQLHUf2h_pjm&1
zqh&!_KFH03FcJvSdfgUYMp=5EpigZ*8}7N_W%Ms^WSQ4hH`9<Y-@eCo=Bwa(J7F&-
z@0Hqn)@Z`(=jSAHT9RGUL*8#!OeK+Eo|1gomdO7>>3061OEcxmf~TcYn5_oHtscWn
zo5!ayj<_fZ)vHu3!A!7M;4y1QIr8YGy$P2qDD_4+T8^=^dB6uNsz|D>p~4pF3Nrb6
zcpRK*($<~JUqOya#M<Nj5NeD+T5x;hmFG<eX9c}=NV`wc<jARp5vyLs-@>1=#IhOZ
zG)W<eDkicrMp8-_i9^4z{DmKwXh5ub#oD0<{P?1u$dyO*+dQl6>+rJS-x(6EoVz)P
zsSo>JtnChd<BA`Ke6ojq<e9H=esJ{9j^XI6oct+80F(vv2>j9^);su%SkFG~_7JPM
zEDz3gk2T7Y%x>1tWyia|op(ilEzvAujW?Xwlw>J6d7<fenhQ-o{rU%TG0yq>yEi8E
zv30riR|a_MM%ZZX&n!qm0{2agq(s?x9E@=*tyT$nND+{Djpm7Rsy!+c$j+wqMwTOF
zZL8BQ|I`<^bGW)5apO{lh(Asqen?_U`$_n0-Ob~Yd%^89oEe%9yGumQ_8Be+l2k+n
zCxT%s?bMpv|AdWP7M1LQwLm|x+igA~;+iK-*+tClF&ueX_V}>=4gvZ01xpubQWXD_
zi?Un>&3=$fu)dgk-Z;0Ll}HK5_YM->l^Czrd0^cJ))(DwL2g3aZuza7ga9^|mT_70
z))}A}r1#-(9cxtn<9jGRwOB4hb9kK@YCgjfOM-90I$8@l=H^`K$cyhe2mTM|FY9vW
znH~h)I<_aa#V1xmhk?Ng@$Jw-s%a!$BI4Us+Df+<tEL-hW7Ms|u9`A#*N;)Maza#2
zze#5;?o={Fl{hl^?>?J&gKAF-M`v}j`OWKP3>6`X`tEmhe#y*(Xm$_^Ybbs=%;L7h
zp7q^C*qM}Krqsinq|WolR99>_!GL#Z71Hhz|IwQQv<>Ds09B?Je(lhI1(FInO8mc}
zl$RyKCUmfku+Cd^8s0|t+e}5g7M{ZPJQH=UB3(~U&(w#Bz#@DTDHy>_UaS~AtN>4O
zJ-I#U@R($fgupHebcpuEBX`SZ>kN!rW$#9>s{^3`86ZRQRtYTY)hiFm_9wU3c`SC8
z-5M%g)h}3Pt|wyj#F%}pGC@VL`9&>9P+_UbudCkS%y2w&*o})hBplrB*@Z?gel5q+
z%|*59(sR9GMk3xME}wd%&k?7~J)OL`rK#4d-haC7uaU8-L@?$K6(r<0e<;y83rK&`
z3Q!1rD9Wkc<?WA+BwMkM^Us)2_`Fi#U;)u%Tj*Mrr)PvDevP<}RrKF&Ui^SxXABRN
zE@bGOea!UE;c~Y#=6~LJGB>B8WBQ|WT|$u^lkr0UL4WH4EQTJyk@5gzHb18cOte4w
zS`fLv8q;PvAZyY;*Go3Qw1~5#gP0D0ERla6M6<d|#}q2cK5j4^9~!z!#57kAw>#{;
zr1l?bR}Nh+OC7)4bfAs(0ZD(axaw6j9v`^jh5>*Eo&$dAnt?c|Y*ckEORIiJXfGcM
zEo`bmIq6rJm`XhkXR-^3d8^RTK2;nmVetHfUNugJG(4XLOu>HJA;0EWb~?&|0abr6
zxqVp@p=b3MN^|~?djPe!=eex(u!x>RYFAj|*T$cTi*Sd3Bme7Pri1tkK9N`KtRmXf
zZYNBNtik97ct1R^vamQBfo9ZUR@k*LhIg8OR9d_{iv#t)LQV91^5}K5u{eyxwOFoU
zHMVq$C>tfa@uNDW^_>EmO~WYQd(@!nKmAvSSIb&hPO|}g-3985t?|R&WZXvxS<ZFQ
zu#EDz3{d_w8RPmHI9?PPAxj~&8j@8$!~cP*{+&2ldOYzckEW7`;MqE<$E8u<geq(<
z5IBRpCLbPpphOf8s@(2^EBiU0RIglgy9;wAc@TDmWt5}Bazs!*l&p@;Wfm6|R(zca
z3J1%F@suFn7(m9Fv{8;0_@9ZU>}Kt2i^eRe>WHb_;-K5cM4=@AN1>E&1c<io+I`+0
z32_B5UoF&#VEpTd-Z1&~J2T0MPx*};V~K5lUJ!1IJhEFk2y#YP7rux(&fx!@Nfs?E
zRtR=}F+-t2-jEyLNV1hGh;A#7Q&S+TFAE->$k!w4O*oscx(f=<1K6l#8Exi)U(ZiZ
zdr#YTP6?m1e1dOKysUjQ^>-MR={OuD00g6+(a^cvcmn#A_%Fh3Of%(qP5nvjS1=(>
z|Ld8{u%(J}%2SY~+$4pjy{()5HN2MYUjg1X9umxOMFFPdM+IwOVEs4Z(olynvT%G)
zt9|#VR}%O2@f6=+6uvbZv{3<!n!IJ@u1~JTZ<i{K_|_{aj<-z`W#jr{>U)l;C{tuc
zZ{K$rut=eS%3_~fQv^@$HV6#9)K9>|0qD$EV2$G^XUNBLM|5-ZmFF!KV)$4l^KVj@
zZ4fI}Knv*K%zPqK77}B-h_V{66VrmoZP2>@^euu8Rc}#qwRwt5uEBWcJJE5*5rT2t
zA4Jpx`QQ~1Sh_n_a9x%Il!t1&B~J6p54zxAJx`REov${jeuL8h8x-z=?qwMAmPK5i
z_*ES)BW(NZluu#Bmn1-NUKQip_X<C+V839FvaVI_NY>&_WzJy~J`WYxEJQ&Gu7DD<
z&F<oG80d~wWIC#R=&LGKUwX37xIMFBSIV$+^x4k%Z;{u3*meTW>9urE;}8S{x4{yB
za<Ixd8m8D*Q@bDkO)*GszSHBj4#O5G`+-cA@;~F2x+d^9<6RR8Z=QY!OE$NCeazmX
z>q~1Zrz%8)<`prSQv$eu5@1RY2WLu=waPTrn`WK%;G5(jt^FeM;gOdvXQjYhax~_>
z{bS_`;t#$RYMu-;_Dd&o+LD<5Afg6v{NK?0d8dD5ohAN?QoocETBj?y{M<zzztwk-
zq**Q}xEOlad^X^Ki>B)jQ%UQ}#t3j&iL!qr@#6JEajR3@^k5wgLfI9S9dT2^f`2wd
z%I#Q*@Ctk@w=(u)@QC}yBvUP&fFRR-uYKJ){Wp3&$s(o~W7OzgsUIPx0|<dx<*{As
z_-+;-3Ss0<Rm`Y`{W-81r24H&VSowxFrE0LYIKdkztmoRh*wv4tc2a0ELz2@Wd<Sb
z?x)~@4x6FZod%xD^|(N=1*H21&y@!)<md6|BXk48O+Or6RyQEC3ifbZjYl^c1PAR{
zilsgrwE4Fe%k7~xA>ph2L1(r*_Pa@T@mcH^JxBjh09#fgo|W#gG7}|)k&uD1iZxb0
z@|Y)W79SKj9sS&EhmTD;uI#)FE6VwQ*YAr&foK$RI5H8_ripb$^=;U%gWbrrk4!5P
zXDcyscEZoSH~n6VJu8$^6LE6)>+=o#Q-~*jmob^@191+Ot1w454e3)WMliLtY6~^w
zW|n#R@~{5K#P+(w+XC%(+UcOrk|yzkEes=!qW%imu6>zjdb!B#`efaliKtN}_c!Jp
zfyZa`n+Nx8;*AquvMT2;c8fnYszdDA*0(R`bsof1W<#O{v%O!1IO4WZe=>XBu_D%d
zOwWDaEtX%@B>4V%f1+dKqcXT>m2!|&?}(GK8e&R=&w?V`*Vj)sCetWp9lr@@{xe6a
zE)JL&;p}OnOO}Nw?vFyoccXT*z*?r}E8{uPtd;4<(hmX;d$rqJhEF}I+kD+m(ke;J
z7Cm$W*CSdcD=RYEBhedg>tuT{PHqwCdDP*NkHv4rvQTXkzEn*Mb0oJz&+WfWIOS4@
zzpPJ|e%a-PIwOaOC7uQcHQ-q(SE(e@fj+7oC@34wzaBNaP;cw&gm{Z8yYX?V(lIv5
zKbg*zo1m5aGA4^lwJ|bAU=j3*d8S{vp!~fLFcK8s6%Ng55_qW_d*3R%e=34aDZPfD
z&Le39j|ahp6E7B0*9OVdeMNrTErFatiE+=Z!XZ^tv0y%zZKXRTBuPyP&C{5(H?t)S
zKV24_-TKpOmCPzU&by8R1Q5HY^@IDoeDA9MbgizgQ*F1Er~HVmvSU>vx}pZVQ&tr|
zOtZl8vfY2#L<)g<P^`K!BdAG#JH2u<JcbXAbC&+5oV4?fK~PJag8d^J(TOIRb!S0`
zS!~~~HeP@OB+QhSp3Z0ptsFe6-3mQ&Xwz!C5}41j#J(-PZ}aCf$d@!;hSHvI6v(ev
z{Frq>Z=ba&wG~EI*Vd?}lRMCf+!b5CDz$8~be-HKM<GBqxLn12;ecxpe^8o7Er@?(
zTOf=lQl{C0cE@aykX2(|HiU<M>o5omk$w7p4`Mym*IR8WiTz4^kKcUo^8Hkcsu14u
z`Pkg`#-Y^A%CqJ0O@UF|caAulf68@(zhqp~YjzInh7qSN7Ov%Aj(Qz%{3zW|xubJ-
ztNE_u_MO7Q_585r;xD?e=Er}@U1G@BKW5v$UM((eByhH2p!^g9W}99OD8VV@7d{#H
zv)Eam+^K(5>-Ot~U!R$Um3prQmM)7DyK=iM%v<dFgt_;&aE9uokCMFF5D+YER%&B+
z1NFlYYbs9KJJsBUmYalD;m^KimIDKYS{_$(*g|3xnAZ3nkE)!kRG!u0q|h1{uhWfS
z@Sz{{UVmFXR*lHI&l6p*RzU~ZBQIT=4==R{7?=y|Sw$sGt1f#5&F0n&Fdegyhw6Cq
zuj5p-u-<e>y>BRX4#aH7*oCMmz07YB(EL!^%F7?CA#>zXqiYDhS;e?LYPTf(bte6B
ztrfvDXYG*T;ExK-w?Knt{jNv)>KMk*sM^n<D*|Oe?Qo@1-8s%l5I3^@<sXv3z4W6k
zubwl}Yz)&G2wPH(mt}WD*_C7ot@91w-qRjMO>gZ-WiUN;=0Ev^GIDMs=AyLg2V@3R
z7ugNc45;4!RPxvzoT}3NCMeK$7j#q3r_xV(@t@OPRyoKBzHJ#IepkDsm$EJRxL)A*
zf{_GQYttu^OXr$jHQn}zs$Eh|s|Z!r?Yi+bS-bi+<K4xZD8$i?u60R!CmjD>PE*lH
zo|6ztu6$r_?|B~S#m>imI!kQP9`6X426uHRri!wGcK;J;`%sFM(D#*Le~W*t2uH`Q
z(HEO9-c_`mhA@4QhbW+tgtt9Pzx=_*3Kh~TB$SKmU4yx-Ay&)n%PZPKg#rD4H{%Ke
zdMY@rf5EAFfqtrf?Vmk&N(_d-<=bvfOdPrYwY*;5%j@O6@O#Qj7LJTk-x3LN+<OaC
zuu1+3D;0A<6<DY!ENaN?+4dznGWKGe;)oHb=;@4zgx#~Q=XMT?B^Lg6hW8>dEKy+X
z>~U8j3Ql`exr1jR>+S4nEy+4c2f{-Q!3_9)yY758tLGg7k^=nt<6<QCi2ReIFn*~P
z0lo8RTEVpW*(EV0rMg_OktG~$1`5dn(L`Yx5%m{cY}>h$YE$ltA+13S<}uOg#XHe6
zZHK<TRwTU`dC1e;NLFyO@(ye{T!)B}+Vk$l{yxy1sFsTf?4}0erchCTvg6V;`p;zV
zc9|tsOW^a9%7#Dvk+Bsk>dNsAnMQ_RIuB;mdoZ%RWpandzLR-BnjN2j@lkBbBd+?i
ze*!5mC}!Qj(Q!rTu`KrRRqp22c=hF6<^v&iCDB`n7mHl;vdclcer%;{;=kA(PwdGG
zdX#B<T=UGU+QCjg84BaSH01V$Z)8EEos04=bp1$qpk;6``a}Y9&cEF|ds<Io?6B|S
zGJJX(0+w(<oJ-KT>WoC!leBC4);^J^tPkPbIe<)~nYb6R3u{HvC!NOQa?DC^Q`|_@
zcz;rk`a!4rSLAS>_=b@g?Yab4%=J3Cc7pRv8?_rHMl_aK*HSPU%0pG2<ecQ6<(S-`
ze1ULaXKO6zV4ZX&kFi}vcgRpkq*4ifp!Qn~2Yi60##6k3n{2>Fyhef_biA!aW|-((
z*RIdG&Lmk(=(nk28Q1k1Oa$8Oa-phG%Mc6dT3>JIylcMMIc{&FsBYBD^n@#~>C?HG
z*1&FpYVvXOU@~r2(BUa+KZv;tZ15#RewooEM0LFb>guQN;Z0EBFMFMZ=-m$a3;gVD
z)2EBD4+*=6ZF?+)P`z@DOT;azK0Q4p4>NfwDR#Pd;no|{q_qB!zk1O8QojE;>zhPu
z1Q=1z^0MYHo1*``H3ex|bW-Zy==5J4fE2;g6sq6YcXMYK5i|S^9(OSw#v!3^!EB<%
zZF~J~CleS`V-peStyf*I%1^R88D;+8{{qN6-t!@gTARDg^w2`uSzFZbPQ!)q^oC}m
zPo8VOQx<Jf9$QxH!1t=XYbND6gD4)~PDdJ4Tbhq5X~|}aMg+64ou3q))oq{tX``B<
z-kJu>q2BaIN`pAVFGu8!{p3}(+iZ`f4ck2ygVpEZMQW38nLpj3NQx+&sAkb8`}P3-
zc>N<oFPq=nmzyIGLDO+Dbl$x~|Fq+?j;c+eUwjpj1>*k6AG?r}bfO6_vccTuKX+*-
z7W4Q#2``P0jIHYs)F>uG#AM#I6W2)!Nu2nD5{<l9!rb#}1|%0Lv<~Q*yx!&(&~cb6
zMP?w40u1ji_FUqt9Oxamq4i9;vld*X{>CRV_PmkDS2ditmbd#pggqEgAo%5oC?|CP
zGa0CV)wA*ko!xC7pZYkqo{10CN_e00FX5SjWkI3?@XG}}bze!(&+k2$C-C`6temSk
z_YyYpB^wh3woo`<Wsaqgc1t2a!^g9^lzKC0rslcWuz#f!+1;%o6gzkLkj=fkxOj>B
zrMSTd4T?(X-jh`FeO76C(3xsOm9s2BP_b%ospg^!#*2*o9N;tf4(X9$qc_d(()yz5
zDk@1}u_Xd+86vy5RBs?LQCuYKCGPS;E4uFOi@V%1JTK&|eRf~lp$AV#;*<!r44#as
z!dyOpmYJ@rJKe3I(P1aZfczZb-R2QPjL1rGU+_--8KLf90ruX^(}*~s^Bim3%N&z0
zs!zTZe(UNyI4Dqw(0b$Xv9j1Fd{<;+*lKW@hWY6lT|nnuK-vY>#O}iRI2=i3rFL8{
zA^ptDZ0l6k-mq=hUJ0x$Y@J>UNfz~I5l63H(`~*v;qX`Z{zwsQQD-!wp0D&hyB8&Z
z7$R07gIKGJ^%AvQ{4KM0edM39iFRx=P^6`!<1(s0t|JbB2tXs_B_IH9#ajH0C=-n+
z`nz`fKMBKLlf?2AC+|83M+0rqR%uhNGD;uKA6jOjp7YDe^4%0fRB<^bcjlS2KF~F;
zu09wh1x0&4pG&76M;x8$u`b134t=dEPBn6PV|X29<#T4F1mxGF*HOgiWU8tN@cguI
z_F@o+XL7FJztR63wC|j4x_DANzcX94r7Iz-O2x$({&qd*mdLG=-Rv)uZ}UlMR+F&q
zU}=lkfb0p1>1Ho){<D*l&HMgf)@%iX&ndM?1_8l%G7lHG2ptl4pBF6lo`3-UP`{`y
z2Zfv97+5c=)P4VQIt+_gnPM?G-7uT~6nc@MeF4;AX@etFIv&f76KusNH9g}81qg)P
zH2O$aR`Fv6A#|^|C-6R#9Qd4kLT08<G%uf}-+Q+cZ+cY6Q*8&^;aCK_XLo;2N#f+R
zuwpXOuPc1L^JwGmVGmH>o$@}mSKIV;h*$AND7~Dl)QzpFBlSM99Kx+F7GsVK5xcR?
z_4Q(Z%cgk8ST}U;;=!LwyZVu^S$>B-Waeik%wzcKTIqeX=0FP(TGQ=nxi=dsS5BYF
zl@?}NT!Y!Iyos^@v7XWXA{_bV<GrjWdOemoPm1ZIR8@7nKZ}xCVskN#la&Rdao#-?
zoUxGKC#JTfdwUdwPl5Q|`0$<5Z)kYdw?GRp$eE#MsvE7Ap4#<a%FgjaO=B|wL}-ug
zaG_p%Q^X|klMZ2srFv>~1lxz7gC?xuXxy0_?GaN!AhRRM5>)^t%&ODd;@HN5L{MD3
zc>i2keQZVm#?NrDwbfd}_<*5^U&w0zv~n-y8=GGN-!=_`FU^cM8oVCWRFxw?BM^YD
zi=<GQTNb_HC3TWA;Y0{o$P1KE6#N+At(3ZK1@l$cT#S-)Nftfb(j_x9*hRec_PUKh
z9*|pB&MLKf$4!Z(eCO7k_x~a4E5o8{+pcGZp#-E;x+SDLl@d@w2?6O)y1NFHknS$&
zlum&`6r@4AySsasZ*xEIaeV(__TE>Vxz4q|jwPTg+?q7_XI)-S@gQkh>w0ZUB}a{^
z_i;`Y(~fvpI<Qoat-qZrSQvl3An0RwV}2eQMzqdC(0#9(VCQdl^bAvlfE45L`W3wE
zJ(A#3bKR(9{Xie;3#k&7)-yR^?cxV&)#YR~o_m+@!;+Vu2H-5g%o8GDgEEx;WR#1X
ziaobU#SE{;ji`8P%X#xZhy)(u4FFKoRP1Ii`V?$dc^D!BjcHR-|0e$p|Cq<}+tCZc
zlUYYw1^}jMu4s~_>!vm<b={xSd@kp5haP#0&d{V1jAHPS(;4zH?R_F`;03zMiyEWN
z!w+KBgX3>W*A^|P7(6+@C4UeL2WATf{P<!`9|SVCF{42tpia{XK_v>1?H5rk`5{TL
zcf!CgP6Mi{MvjZS)rfo7JLD<Nm(AUvbjZ}D5Q;$}b1(`wkD4|*ZDw}~-AIIXu?P3r
zXw`Ru#-yIg);l2GFEWd#Ie&9P4_SzkHVy`b)d|)X<1$6SkX9=hpokm)H(E3iwyFv;
zY!hF3km+Wb$O0}Cd!z@4Emb+k2qCxsU{$RuEO^G{#K}sZE%EI_ozrN|m!(DC72LTy
zmG#(m%U{ZpBL5+7gdlx?<3m?qxV;&m4EhucYZq;xlPU}Z|Ig0gx4kttKWc}Tv^4+i
zj^h5UH&Jh;zk?bHcSJM4Q?bKexQa~?ASj~Gs|xzCT(J5J9?x+h7Nl_dgrGH!p4J&O
z>ZK7M7ANd$3`{j9baD*7{#Zu-33fOYUzjvtKzR2)_T1I<c0gpbBE1Lz*UlmX%FmE1
z%Fj?yG&TRNNcZK8i?VcBn;5OnYm^E0^YgAL1?D)(8kd+@rIqk*`X6TbHuFB!bZeQB
z$$8y2_z0IdLQ4i)9LZtEVf+Rc^)<AHFp4XYDct&5Mc)JN@gV-oX6el|&`v5?ZmLqW
zc80{I_4IIWG^kGVLK%1nu>1s7fe&z|=)QkX;=`zX8!Byw-veM#yr;|wjO^II>!B*B
z0+w%;0(=*G3V@88t!}~zx)&do(uF=073Yeh*fEhZb3Vn>t!m(9p~Y_FdV3IgR)9eT
z)~e9xpI%2deTWyHlXA(7srrfc_`7ACm!R>So<wwK$b)hOtc@9M7}H@dlj?5*aEXEV
z4f!VOylp$^?K_1-0#xm1#TTS+cBsPZtjk5fiyD&O|H)n$^Agx3|Gtb?W4r>IgkuF8
z!wkOhrixFy9y@)GdxAntd!!7@=L_tFD2T5OdSUO)I%yj02le`qeQ=yKq$g^h)NG;#
za(0J@#VBi^5YI|QI=rq{KlxwGabZJ0dKmfWDROkcM}lUN$@DV`K7fU?8CP2H23QPi
zG?YF*=Vn=kTK<Di2(U=A>*#Y_{AQN&oLju|0#E=fx%YVh>S{puu&K$b;BN*jIo<Zz
zzRGrcG`rdp^V2?x)s@C<AR=L#yNlXfd@$hV;Xs87V{)V7jaj@zp|zEr8^(2pM8&Lt
zY)IA%>@VYhqPiJPzzM>#kxoy0vW9i;ne2_BIG0zyRFp<3M(iY(%*M_>q0ulV2K}Tg
zkG{EWKS{i%4DUuHi%DVKy%e+Q!~Uf`>>F6NgD{{I8~nO4!VgOvtFOc7(O)X`|7n*f
zxBa4CJ-v9fUUH+`7sPVvpM_C*udZ@OTGTzx56QM5y~OlrZc&w9=)B?nmd@keRn+^=
zvm~4sa5987L<xOMsN(kDq(KnCe@&y{sr8G5cRF;;)Yu+B+W^sh9NRF;J~Q(+)H%#f
z$Kph0hn^yD?j1P&H7y*mLeFo*J5kC|GDN`i_L=y2L5di<0&iZ$+{S&r>FDnU{(N|N
zJAR8H@}p1fC+H(yTI4n#%~TbImMpuqYn9cQ<0QQ%=PzZItLkC*ef9WJUvfITKWh#D
zc#__8`4am9%#NslIUw+<82#SR8AYG|woLfBg#!-&dqq}@P>|I0%lbdy0lSMmNe+}o
zj0zZuFr6Wb?Y{Qy-S=|r`bdrDmhnmvkRnkdn`YCleU>Q$=je}LGhh>_QAj6aa_0Oc
z%Swsmui;IRx7bN*=AAS@5yW&Y2hy;3&|HAiA8}!HT6!Z!RVn~MZg`RmI6&%#tBZDx
zfD+y@Z~NWlk*4l13vmt3AK2wP!fQlnBbECL>?p)F?T)<`w&QN>cP_V>r7UTcsTaaP
zTOb$f!P@zf$6>890NVKbIkG8rE?9<OqttRj(-ZK8f%}9p`79lS?>!Y97sMSZjfF?A
zYR8l<h=2$V^4#*9G|J-^Q7CnT=tr2LIrsKnEjBOW8GH|1A4;o6@qTN;6mJCLt=kf|
zh;`^g^TK``40;4_<hi(6FKtHhAPLO|{KccsHH)_i01g$RE)dx!p7j1F7$zamkN<D_
z@|Cr>p`LMoz~O?iaZN;gcX;LC-%Ia*R%A&SLx!YIf29?P+=XAAojK8!^<h1{U)O*W
z3U3~v691kJ1v;_~`1@5lj>OU*@?R&DK!#G_lsn!#;S375uZ&B0HH1|BO0R90$U>qs
z<vnMOU-}JTrm#3ef@K)7UlJr}>SvHv>H~mAgNCcjo-e+;RjY6B9<S}C=_0?vC5S&L
z6#AV0@io_9FBx)7f0)xYBu<`-jOUC9;s23eW26F#0KrAT%axw_bX*=yI4l5!fHVF6
z`1Mj99y1NS+RGeP8BlOP=;n1J7J#q^jNmrvYh`dLuV$nE#!0`zMocVdSOjdD`0VEH
zr1Ps(`B`=kk3ZbXL>NCbQrZ|BHjTkehaU<9CSkdd>Vl*ifA2LNOP&R2Qdy3k3-TQ+
zbq=#vI43x`s=%~cGyN&y4Y!FxhwgDe@i6uv8^BLL&3z*SO=D0aLjih?gY4-<y^l?t
zk3e8`;$%Kxn5g;jN1DMxlMjDpdi0&aPG^&WB@fGT&~65(@|xSH?el!AgVft7A4zxB
zq06hzaAR3oP9Rgs4`RF_q5$9whAgHJQov-ZcZp%fE16#_MHP#};;p0kzf?C)SEIQH
zFg@_a(8AIuH<G-QfTgMS{sy4d!EYo>9uWp5or)H+v~w6n5X#F-I52z=Z_p4JB(;M|
zeaVFhuR2|3UD2MzVc~^nSoD<LbmC1bKfM%DNxB8FwTuG2brrI(GLY^!yEls)PHDDr
zDX+M703dQBayYBlaEqoO#vn|E*nmjVpw9BN+H=OQ(g#1-7YHClz{W`!w<lG4568f0
z0$(A}c}>2(dD#uL_1Pdn<dE0I#JmiUK#=Z()Pvs4{V@B(+?^oGlQ0}@vI5=j=SW;?
z%j1_%``DjKz5S8};=unJOSJLM$u-t3xb7Y<T>IxeA{V5n`#3xf1Zx@4lw(DsQ&H$h
zw#%3O<1173hjg2_nhKi!d1ej=h7y`hVjCNB6|HTnx>SWuCE-kgTnfT+YGX4_Lun({
zDv2`>d3vrS)tTf7ps_vvh!Cx^e1BFuWnEAh0(7fkNk|-3oU|iRWdsC6U)?Raft~HN
z;^$U}vZK5O8|LV$>6X5T(uYkblv{zwPxnQBh(BQ5tA~J!vGiAMYP^_ki~pkIxDfOZ
zUJDwq%O~WueeV6%uN<54&u*c&E4y431cklBNrb06zGOOy4XNT~JS-q(s6@)F@ovbe
ze`fial(O4(-su%6@@1+V0MsdLLMyE8;)nou(7}czU(5ASaZYDT(kUZ0L(&g$nF^n9
z9-Pi`ZZLX&)^*M6As4_2Mmc9S7OT)F8KkL2NJ)KJcnCuWU=Wy402A&45#Q9Id~BBH
z0cY*xlv!uXzKrXLH!xQu(OtJvEj|0-DmRj1vjFz{c*I4$Pe(+_V|^b~S!0xm{8lq=
zZv)@NlcyL3Xdz+*|L137F7y6L-2VsrKw=q^S>F6i%<{Fr8<WM{ts-vCJB7AA<R;-Z
zj8OzQwh#a5ur&1^JP{uiVk^%d#slE~PfVLhx<QYYzl~0W0JRT^4nXv}egG)hZndvo
zGk!SAt87w@&q7!{rhWGBSnm@Qruh$t;;6w-#kIomVN8LS_3=Q|b{^qJy<`35mH#2$
zvb^+6X-)A`xs9T#rD!k!OY}dvdU@6##IOfk^;z7+gJ`z$Of7_it-nT=!8!Mb@y{n=
zxKEVnv54AzXV89mWl&YM)Tnl}j~*arcBU7n3JbFV$dC%XS^_o97(kz#^7MULgd1|3
zz3{di(P_6}-{4oyyT!lPd};kb_ojHiv}f)3ZGs>zk06$Ay-(!L$fY@7mcng!2}L0t
zgi|KxfB63Xtk_Q8#ZP<GXYHJ~y1J5@LvGCA+fiog-K*6F{#d-v4~}DVo}a^Me%u~h
zk9J3H_IgwEYcHHz*BY<&P-3MA`vGVK(JzlCjXtv9WmA2-{bTjny#LYIr$ycpsfo_A
zKv%vCEcY>ipQ@!zgjdpEIbK_?q17Hoi4Eiyun$hrc>T(7pOLVLQE=lgGwA+A308p&
z7@=09(|$>eLy5gLe{*|3b(M;1n;C^~v?o88jYib48eR4$QGsBFzd}3QuwO^_XE(=B
zq+hMi0UFC|dB{LCwch7;zYT=NK})O%sgi0k#yV;My@24^B1+CuZmYOh0^b)5Ba_))
zC%i#_Iev&nsu%I|1N5=MVc#PrlunKAs&hY|3<u*}B}09#+tJy2i<?Tn4Iur!#);dW
zgZusa=(teXg;7j~<|h7lf9psCfEglzx@i=(FM(NP7)HX&j69I1+4F{thHZm=6|(ij
zS*39m7N5^twygWd2XM)4MbiJFceCe#a^o_3tJee22Rr5ZDT?df7`7aVIQMc<Cwhu)
zlLDP<phpt|;{9L<%;a5!NAa;T$n^<A^8R34cl!Bma`Qj}Uuc>s5;@}`>sB>}gzxuB
zB=2vrRyB3uiyW<pr?qBXrL?>(hkDUNe1@&(b`;>ZvGgw|@s{zVC#_`HXIN_^J@Etb
zA7A+F?ot37T{<-vTy8h&b3e+WKHE1oh;pUQrN4yRRrx?mT_9jRa2i4l1fUnLW^Cbl
z!I1>VzyFe?VELWWhM?@?t-YPZkD-Qjo@bC2(o#ZtZmr{KZsdFWItV`rs$gp{724@C
zL8K5}E0+DHcWcL^{BGei4>@J-3%a#$y6;I}=upc};-NDv-z#kPX26ylOpH)Ov1uU{
zkLj6oiH6l_s+B~_z;|Jc2oi?naS7#3H63~~lWj4rUnd=fCnKdkik<@R&kch9q##G{
z4u!%=rlM~Yp3jk*t8}1B`Sv6<%Z^}~1e@aq<X7riC~1(P(DH@8ivif@)OH<{Fxu_U
zmPNqoSd?-iXeU~dyJ-Ie!)p`a2e?X8wSJj8+@F5v)Hv146gqWWv;?lg@6wY8NZZ{>
zg|JQ`QO2pSjAm-g*?IrNc$<O%@Md5UOwkv=LlV5T|DIO?&U_OUPzv(p3&&e2GW%VH
z@$UGgqu`N&&Tivstir&k_EZX;BGj{vr4t}|>^~sIrNBo2$m|Sxanr?Mfs>2@Auu49
zGXlsS<9XS1&8h(dD*Hl&5HBDG!^pJ*lkau_Ur+7`7z;rcs$hT4we?3bT=7Fe<>{5(
z2m2(c+hUz2BTHM8d<w9V>Ce*Z3XX&Av;b~a=$6EF>&^E8%nyxO@m_n<s{kYz4AgIR
zL2NoCxZr(4hi(HV=Z>!q&XD^A{SRjRZQ0L~qDeC=j&0$j6=LNIz@`ni^>ch|sv}^6
zlm>?28yPl@WmDPR?Y-A9X{U9Dv_IsbXJnzKCjkRksL<ezzCcRL9w1`L`S^mg@ZD(f
zhtt<I-~r4g2c+cLk)GETbQ@*cZS6Irpwx%I?attLUeje!|7FO^zn^xQI&NF~7Bi&+
zuM83k*@|tUw1uhVgP+@xciID_FPi(ym#Used<L*hvb1QA4#6ZLQ!!N93<_jsYom|Z
zP*q}T#kI!s;K4sCSn$He-@i|5c5>Og#42uG2mE_acbTQ4)J|1V>%U@K(FP3AYhL0U
zdeOCPN1qLv!|#c=p!_+%VNV(GHt`RuLRV^vz<5tt-r)yOK**kUWPspVAf|}ZL{LS=
z@k(@@!P&W!>wwe`x{+GrFSWhHov7hu?{KuuT%kl#WO@*WX$i_@retlhQBj++SVNCx
z5$78LxP>Z=^aJ)D280r_jj=zFfMJFXCIe^B{~V@d1rl_F(qo&AB4bC-vYL>x2jSKX
zpuTG-6kgp3e^T&+dtV*i6a~)v@n?n*<z->MffN59y}<0dj<e1F<R$Ci;6PyyM{_cK
zV71BZRI)8Yglo`qWIFif?ipY!Fni#(;o1`0e#@!ow(-{uWmLazz?Kl6IQsE(uy3NK
ztrFu2s#NYVou{VP-;#N;IkfO89yDpXPK^?qNmsu=?7p0kh*Eu0;q|pJWMhZV4f>UX
zt27R+SE#hp<Lm{tGyC#7E{ce(0_YQZM$4z{o7Z1`AvybOyS!e00nb0C34Q}+!r`aD
zpf`Mac2WC!%G`LV*pM&LTXWaX84{D9G*D(FVDQ_bt?mJim`l!B0Z}vUqmlqg0!*^O
zcA!Q;hqw#$8Ao(o3Hpi__#Q&w!Xsm;P&9Wec^l(uj}n=Gl-=U*thjru8FrQ_Je|~K
zp1XUI3e>8bzc#;rk$jw3r4)Q@eI$*`_)=Pvge8@8|8>H3X)<9YX6cXa=ii#Le;(<a
z`KFRJIj-ffCpF6ENMIcEcU&$Hd;|(3cpVlmvy<LKm)Jg`PbcRwGIi(`%q09nT&_zF
zvWSvuKS@1qJl>qKm@%0-7$>2ShnYc`j#zJ7gu_FE^?uAkL|H)UIH#gPu^40!6^J=^
zr`}iwa^!4tzW<Qt%a<<laH{7_zB&p(0$FPylMs#J0s?N#bzgbh&B$b;2w2TH(u#xX
zR}M?2ymO*H#ZAtff0x8nn)XyVVRHyh_o9OC1?w9D(!n?LVed$yyI)eXw7**a^W}#V
zyBV?S1<81#@|akkAxc^KI>~vOMZAaKF>*8A{^8m$i(VK)>?=#l`xrVe>wseSvM_aF
zATNkY><TQeR9<>kM_P3?1kE`uIq#mvr-wuTgUH0N<&JhF=(E9%^NS*HLm!4GZ4_XI
zL=R5tlG5Mk_1rPfg)sk^llFuKPMPBhuU|L5q#yP_mzxp1o&pAzi-X31sgFpIHn@($
z_>=`AB5(8tP6p<?8(2xdNNpl%0MLfNZTwA&9rBO#uTq#Qw^QJQ)uQ2s#I;Qg_&J<D
zZ&&s)bA-~md1xHINT5&_nLww5su08kh8vapD}I-Yp9Z_6{QuajI>2zS5VEvH5J$M`
z_much3>S7t3Yo`Yx!>83-hW9LYzDKP?mKdkD#QAK8*M((sx{eBQdrR<^3ZhFP81+&
zBn<SQWvqO%c}_IG&1NDZ&bTP}wC*pcl?}d&gh50-gIRZkXfi*wUn71FcE8OaBZIsE
zV1*QqcFBW8x<X~A7X$Kv{#qoJ?0O~iH@K8=!EU!pw^qLU{)n%#y+zB_i3v+VL3{it
zl%R3|Q!SNkg@K>JMUefQyNBj<DZWurg+o<Mr21=YbR(4xcmG?w5EPT;zl{Iz$S5f}
z2GkRQ=S=?4xAs@gonS5bCLN9^t=gdoRO0q6UX~h7*am$V3a@d?)Nw?9v1kUMX#HBt
z_2Ms!?Gu}}ZyUeZ$QguJVP@2wR??NHp*(pmB}T#16zydjLms{*aUR&bI=hroFRmoa
z=93={>i~$5d88Wfw1Lv59aJN9t2!pABLg;ewJ#LXL-10;QcJl+Y4M<e0t$@U?O%#m
z+}tz85hqk7=3Oh8{Tb|GY!556)0iG&lr-isk&QSmue&WHXFV#NV_2gc8t#*fn(79s
zU+rg7xM@z!+)LZSG2Cyl{);jq1c-lu9NJ&JW0|OYgJqpn{!RJ~RK8aORtcw0N7YQm
zXvxyjG~t;EQDx>tngb)k6JZlCf)3uD_u)J3s<zJVhL9Wemph~5E%9-LEvT#|Xg(;e
zJ5=7sFIA~H71xlmT$)!qdH7rjaitIUt9L#VJY`*(&f)#e1*uuZo-8=ixFgtL%mrqA
zQ3R5~o9o~9On89&I>YyN;NN5hNbg$%W!i-GK%e&!Us)2IExWSss$YG(hm3kJ-h%yD
z>8q^n$+4I(_y_mbT{du4P%h1j3oSpjhY97{+IZ`aA4ug!vNJ6*p?<2H(2w+GD3j$I
z1TUXGyNzdf>_yB3grP~FZUs<2Quw;eEi*7s(-MiIkQ%@J^+WGdQvYSUN+TRiD-xto
zJ=OUU+kxGYc!HC<pe#-^0;ZHBgF>LNbCvR4lGTp~#L;DFzGd-#gJe<tAL3ntTohN|
z^FZy7ch=Oj>*xf(P3hDQz|y)?b9mwU3WUVnpcqXM<@w%r-k*Wr^gzAv)8T^sqA=Ye
z!7qy&exJmAcAt~CwS#@yNmjr8*T*!A6w4~E*ibaLRs0CFo(;R3=ODhDt6zWNodmo0
zXx&bT$6&+5c>a|WJ)F4G-^GjY0H#*tY=UNyYr_q5fsrcjk(c^~e*7Lf`!Jd`)p412
z<z*QcFvu`K2N?SBr`tlvW^?OESeAhGV2z#~pS4!+J9z14MVqidbO#Fj0Y*Ypct6ue
z@eeTZl=LCDN*1pZB#Gd8=Q6CiA-Ep(J1yr|l_|r9K1Dk40B6W7)bo37EauiB9n4K?
zv}7gy6AG;WUJqa(AYh;ax4G!MnTH=mV8{GvA^CO0D)H5#y#c_pl2KMV{{4@&OB6cN
zif&aC-joD5$b54{^;;(OTSTIr-$17f#hh*x6cx+d6gA{Z_nUQYkgDyZ;w{z#_tHnN
ziM$L#Jg`ul7XvNf5Z2h-eA;G+kR2z^0&P(W(E9L{=}0A{okOdP4U!XjLG>n|^*hV=
zFI4UbwA%X@smDd$cQOiMC%jfitTxTb+#`9`G=2rJDfK!E=5ra|So>lc{X1$~w28i+
z4p&cTGwZ#5VueiXS9O8#;RR$yg7tL9!^)Sz&pZYIzlSh}0}V{LxL$Cu%B4U5_}k}-
zm~|CsD<076x@<>m=6w6N?<jtJ7_!*BRP~Red6W5UH?Z%Qq)HZvu`S#Wb8NZqT9TEW
zZUmur`|K~aFkFcgu6!dSGiAA>WaThIBP`!u{-;WF)xc=2otx*lwf|5+MkdJePjh(B
z9SH+%<l8+=TSp5{izBZ*y$n6C{R8*8lQGb1+>cHGCMAXNxB{_3^otDWdsV7Ob6n{0
z+&!(;iaHOX__5z_$Qk{%xYV%Ig@7iokGBwR`3642ZP#H#v9QGbWl8<|MS*=@qO@Uj
z6+SZ_v9`1paUe5tFN~v(b#J3a_Lx0+;r9giZIx-A5TxdbG>xi#AZ5_z1V}B^n)sxT
zz49}eK7EWb6wR!6-qQOrHQHkUvshvq%=G2d&@(#XM*Am1;WbnJ{X_!a{ZkphD$^TQ
z=Iskb&}=lBm(RHiwJoGg`*NiQ6#RB$T#LF+>#ef;Jne&M<VvOah+wY`R={-6k2=lR
z2_t5IQcGx5C;1n9Y8D^^46tj{Y-?*H<l|tLV}Jx;L?kf<vH;OqBCoOUWlgsT*srfb
zp#_n=<e03}=HVG6MdadI4$r;WF!;h<$YpwCzT?J<doH5%tUG|kUh~}UOOEc7Vg3Ln
zn+Oec{Ja@~cc>xKPX!#r`&TVEFsp2jnNx>dClzpcPy&G&13a_<0qaR3i+k212~hoQ
z8n<!aK2raOiu(^#z)w4cfHt8%7H~=DX$!i<ILe)$=cRjtyK=era@8gD<)6oPN#F#M
z97_Ic)9Mz8um3Fa>Mk{JP-t04I{GW5gUBqcJW-jSMrlw}>p)ptx?WKuCUV77taMiV
zHok9V=6yv+Uts@fMY&A}amC=!Yj}eL@=e%XJ#%?agkt1jWF+10{(E9mHLDa>Ll7Vj
zG=3cp%ljIB-6pC}6&`xJ*6WCP|IlglLWJ^?yviI8Ve)?V_i4%n;olzny62_`-|IGi
z^=}p_O>Z8M;c4|RExu70E7ePW(HWVS&E$+LL6xSQgB`QfMQJ|4pCTFowA39p5P-|$
zUtM_H<g}qAE_sVllCG=<M7JsGdHHhhU-UC?0g!wiJTfK;FpH@Q%+(F1&-<x!X@PgM
zvKCR6P5<eQA@iw-lA-S1m+j5JNv&=s$xGjyi3+ZlOGh=dw>2HnP8_RoS~Vwk(FhbG
zH41licj%=0a;Ln2STFBvU}Ne&O&%8bYKj!h1FA#sNM`232fX|U3QPp#3C?mN2;hE9
z;)!@5ixSPl<89^7gwhHc2YAX1KJK$#*3`KOMIQ253q7-*RJ5k)zp9GBO|Ga~X*^<w
z66A&v#A=l-eXA_Ad|ec)K5wO!rk{{6$Z2+xfF5yj_W6dPtx$bx^M*W?&|yWDCdm^_
z`LxRMJDeH}kPFbnto>}US5oN@aG&waHV<JwM9&yg%AbC~$YEKY*FkLhPUL+pNVQ73
zUzM+Q+hOAq*3!LAkL1~7j!rD_&dV_Ot|!gCHTm4%Mu)D4HK(-n)c!S*RL8%;xcMPA
zHlfB<w<WQA@dUVuN#p&3=a)^rQNm+Xpcc4R*!kw%jWqrW6F<gw>%vi~r{t^`ptTxb
zL}q1W8S7*>7oWwvgV4uFLZ(@k`R*=LO_|Gu`prs~!WQXj-NLIa^2(<al;Jh;hQ95$
zPQ`kpdv$S4vWaain)Gi`v=Od5g!4@`PX-k?)EXtfQ(4{ZZB#~+ujH%%>7IHg>BG^N
zc|i{-^=&Cek9dkJFQys|sjG9i>LLz|;yCv{^1i%c*h>8zF91kLvS9HBQi~ZU!JL`B
zK8N+U0fr1*6??Ium)AF!6tc1eGhXIYL6IRT7rmKp7+>?%5Pa6zC5)KY$ycF0<l#9E
z$8B4tWNLL==*Bm>ZJ`G5nEQDG100U-jLkH8^UE4g6wq?sg%pP=-$&G#bcN`^?w3a6
z((s$6eRKcSEIslW-kk5Qi|5Mg-(xdLF}PxxVh$PuO}#aR6pW1kV4Af!Bqh*btXNNZ
z>-4(IUl+L4dw+3LcpGut=qB45O+W)Q5?*zZ2A6rJcg`qkSvWA!j^r2mqKuCm6`Py?
z@^T#Ux04HemPGd!Hs7NkZdVn1<F}@~Qum4opUXdFj-(>}8_j`o?)*OKZGS!`ff)gF
zG?v-lj$wWNWCcw2Mg2o18D~1?3_b0XzdiKBNkYSDpcv@&kp0POmweJE2ZkIQ3B!a!
zIgIoE+Xv?;34kyo^QYjZk+tEqZvq^#QG<xY{v9%{6QU~c%Cdh&4BPnAYMOfJxnMN@
z(1}k9p~F8K(iCOC2ktHCpD$HvCF=vJT`Bg=K}u&ldt~ySLLegHqE{rGx_^8@MEEU1
z3PuU#M^ZbXD1)9Mtv_mH@xuPKpBpS#Wgsq`3aZ{KoX&}gyn97jT{()LX<@?dTV`Y2
zXOg^-SbxMxg6gNDf`8vT2<Lky=;R9HQq#w)wp(a12Og)Lq43-p0|;1)+pf3(=HS@@
zx;Fu#(pUh91lG1M)$*65aOz)H{nRhMspSvDi~#|q@hIP3$@l$}bsa1f)!~#oqSgaZ
z`T6}OqcHr-RriMY)v=`W(AZ{Ywm9p|-xVTWnK*L_u*ee+9ar+4zSO-CI)D%?5ZC?s
z8%tIWI47EE;m1qRZ!oF<uEeHt$o{z6W(#RPouD7=tg~0@Cl7T<dY`u9UQs8Lpsf5w
zE1Nv{+RM>(OzX4~X+KtsoQoddTWUR(yo8R+ObEF1j<-syWOb>)JQ&Zbdu(sctU%Mt
zW&YR0{ttY2TTXYZ?~WNU&cES1Z2q(7SrWDh``!J(JM+Nk$!hu&Y;(7E`ZNKTe0w+%
zJc?Qnw2B+%UR}0;cB0Rufa(7-3FF}?629@LgTiEC&2uyL6NxexOp?AKT^aAx3gi(W
zao>r>MPw0eQ3>IV02uLsC@>yK_epX6GRg4{NEL2wPPF9=*L2RV3yyK8DhuEK>rmmV
z`&Q~#c`lgR&93TdOCja|ewOXmPNRh7!&dMT(1ett#iDr8HZW~VqWW@7fe9B6;7S+?
zbC`d4@MEau&mKlOPKd>*10q0c{~^baw6!a*w^sY#0Xim{oOsiXiDOhbG&kl3c$$n1
zMRrD83&QucDSEcV*7LIp8VTA@F<%qe+_c`L;6on(>SjAU^}5c9!BCffT>$VQhe=)z
z8(=Ej{5>jhmjB3{xDfj2R@VmHQ!CqjlO4KnuOmvHy3K#po$yp_V;p_MKjh1`(rzj6
zHW956k1yvntz{_g?<K|0Ox;ldqz}7~sWiCO_;;Z$zeJbZ@*_=jF5aD^<z=xsMFc%S
ztx8_QXEl60TW_5`$iGSyg;56v+mN`-s-vgcQ*TzQ!o>Xbs`avK(IjlTnsu%htO;D7
z?J#x^EzuvVn&NA=<!E-%FlSm|&K91xLw{Qo)ICV~E;(<q2m!O85Q?$_H9BE*X|1#w
zLeNDo#s!%<egse#*9CWw^!b0jIo%lkg#Q_!&Yg{f@v$uT2&E6VTB7rb4sdvRre|=G
zf4mzEdoKK;IQPOV;EnY9{c+_(Snf#dI}zxnr8$0>!MEj7cwe5A-Z$Zk2LBZH$~%E*
zf`((xH0?`}hs|HA%mtwfOEsZJxxrennkTYcwP#FKO5%Lpc^JXhSpV|ZH$Wr;`}`_(
zIP==gd3LYyVtwD|*ZJGi{7~x8{=^bGVqu0RJ`n_BZH9+}kz%-4ZRsImi@rx%=ZEKs
zcPnUXo6hbJV><N0A2vUl*$<pju{|4nFdi>fH;@1|bAHIe0ijYI*&kdT|HkDS$9No9
zCHo=*HWb~U+Dtzxr+Esao}6@|;Pf+E$ay0$kQp#s{wlw+7aIKbMdf`OqhoG*;Tco0
zjrP}VQG#Y2cJuqoJg&5({)S(BA}q9T1lGeWRyu=Je|)I!6a+aj!IP^1({)ZYe&x6w
zt3a)Dq^TB+A7CdB0-}#z2Ur$W&h3YVw8==!xONy$uQmDWh-@15iEOt!q2m&?ZLA|w
z8loSb(0}7y6Xu0?M5Uf4>VZGluB`wMf2oh;m)ghxVda>3m}4%V)r^0nVQ5V6f3>*)
z0&VN!N0~GC^P}<TFeKN%{QeEFU_iG2Uh3T9tar*DXup3XU*WWxAkMjtWvbC~y#F(j
zEdC?Zjk;Z2oVOCH`R*z-;Ub+_TSPMvK6o`ggXB&&L=-=F7VZdUn)2Jx?{+*J;S1V9
z1(1WVMi-C0ibg>vj$`EDMZEmVV;N&RISY2C;$0;2(<{Lt&PKzqRByQdiEHGAbwtbS
zPj`Da5%U6k1oEtVzI}QNw;!hT6F+~|@=c@$C4NtO@=xg<R=LN}&n=y^3--f}KhmTx
zJlhb1_I`QZpy~R<_jfm}=8M2C8nT;V#Pb{YUQGNw1xpn$LJkx_&Jao8d%eNNCCwQ@
z;V9_s>P?|5MyZAyuCzcvq4rdAv@C06%gZ`9%I);R6UGiGJobfux+<0DLS&|MSG4UH
z_~o{^^9>ixMg~mY!-@Fai{xaE4^;qy9iZN15Gbn5ZqHWf>Jc5Rv6(#n8`1NcCsdmG
zab*dSXVPaE?)wCalD;$ivF%@nB#7D`@YG04p6ed9m}4iJW|pfVMLE<-c{=-8$e?cH
zUd<xThhv*8PHrF}EQ$aw`*!pGq=k0G<(!Po&%31`yRF2%u|hyZ&kAMxei<J|ktN}M
ziKVi09S!g-8$OoH&v9vNRF*zH+u8?7z4C3oU(Ix2_0!gdzpWHs4sK3RS>U#mCj4gb
zZKA^b9p*9S(}8@tw~1RNPHr7tQr;<ZXj9xn$qLL!gq8|;Tpv_V3JQ`=ywmjF#7cEX
zkq!tcOXPL=jU!}4KzsN|#f}Gq)!H7jJQd3J?^gk9B(nO>P+-)D8|sq=*o)G%RGqt>
zzP5yf`pVxb)I51D_G<k*KI6g^jmM(TL72A(ECxqI<sKk)-5RUGR&&M9f*>~Xp^GNK
zVI6sAX)a9s)e{8N3?35YA6aQTXuy<AK9dSdChZK)kaIam{lV3ngYU-&{0&Qdz5;kI
zUN<)aiwCow)0PV^Lv38uQCIBfu1twu6BlNbFyc|oF_XDvE-C)ukDdpWgDn@&e1&<0
z!!hPP)*>szK3ah~CemzA&CII#8F&F#KN41~8I^&_%}6MCNb{W87qAF`zj_Y^szhb>
z3p3}KbOxot<VQxJf=a2j5NrL{Tj`6rUr1e=#w+H7?q~#YL(&z{5_6s;_Yp{C`$&w=
zCba(}o)j#3NpnixD8=Lq@%tobLs=fa_Er!O^4QFZ`M#0nhyPr?wtXUN@STUUCL;=n
zI8ceLKdEEmFSYl+>Y|(lD=;)`fYE_*{S}x;f^SW#)SU&5X#o|-R|trpa|L5PS5aa0
zTHw8%SDSVtU4?vyrhnq+^@dgFS)|(y{~(4j%3UEiO-rBM9%`)8(dh33pMLiuurNY#
z#10AsQ7%*0Cu_DSAU}<dhwPOA<yIDY1$IULsiwAm7iT~KHjq?;!9Zur;qvF;)MA4(
zQ(~KWrLvCaB_4k-y9!0sxXW#>P;X(JwA64~Q_^R%d_zSm^6Aux?Pn70PM>9EvLeOX
z&w9c)pGmc<dO<uA92i7rFmL(|A5QN80{Fb2^2uN;&QA(GDRBuVh5he%Tdl5trM&dK
zJ&BJ8D;H&X?dsj$-Zmt7KWZ9&mCb2voEk{0&YN-iP2qesrYuuvr4n3O*j_$ZGFCV;
zzcM+8UZ1h6X!WZ>L2<u|`$6ePqEDh9FrjsI|D;ymvu(z?(H19y%V0)kIpMuZvvdQv
zo8)X710!C@sJeuQcJbaoZW}z}j`f2NN^3_>2;MO3C_B>=NC0RJpMp8?#ZUf=GWRvy
z6RHq3B}=MGVg?9@iKFBpsvnkVh3{Vpp=`CcD=u~@ql{my|6?3ssi3mCOPnjI&E}VC
zc@X+Yl>;;DNo0W0`0th!X{?luDhOC<mZsB{{0@HyWCaBiPfBpW_h;Ei%7hIV90wQm
zIY3QNg%9*AwkX|;Ma(A!-Kx%NN<?ihrc`gN{agdLBij*zvCQS88ls4kC09#bZHEzC
z6kI%SG&IMOXfbaf;7pflT}lW!##~DzhUVjY9&~hoth8OjTkv>{E8N=?<oG~pbXEm8
z`T&`6nOPi8i|wO?8bGVJPk4;XbZolWH2yj1dl1;}<CbxN+qd{O#9M6OQp|?}QVy*b
zHmo<qFOb)6zPQ8XMNItr?B!bV8t2_q*y*_)QRmV9uH4xI(l-Ve(x4wt?I^2kzr_VK
zNFt(;Wp*#?gDYl-FsON_=&?nA9ZqErp>!w}K1{V=)+1={m(f`Oc|N=07>}3;z{-(A
zm{JL=j?Sro5iecmE2-pWlRf(r%|HEQ7kgwQ9+kt=NBhtQI7OwcZ#3%$Uf%^r2nhjY
zoQ08MfC%_X{O9~WcirMZMhn#z^ux4Erx-tf-6bHD)9eH&^L>^jvAd^9A^DCDs?0;k
zkm7LE*KjP6`2d17M<h~@#0><GFiRFH&zzgiba#GJ@rL^eQoLKd2iD|5ximFPfdGQC
zy;ur$SJBzbNre##<?L%+Et2mwm&yc!_e6k$?h=6We))18ak5JUQBLA$HXhAa6!4{Y
znw9`%60lGBgpZ(rq>rQaaLqd_Rka}J$csvUec#hw78<=s(hyR>065~YCVCA9+#Q+;
za(*<S_H<0lL)lBP#x7J#i}k!_F3woldM^JpLZe8?EDt}6{10mgE)7)bbij$P&ZETh
z%ukHGyl;8J59)UkZkXYHP(Srz3E=Yji7veb=J%wZ<#HaU3^xPi?0dZ54F;Q`gaj}|
zi#tVNqwEtCQ;q^MG-}ZRc6gCPzGJ<<Y;YkrKZh~i5A_+5t#1;8yCnJdpHes?9gFWt
zvVG`M3NdNPW2FLd$A<j5<R`D|E7ODyYu|rOV0;TOH9i>L0IEw!r5P|@-;x33L$Lv9
zcuN8YG&g{<(SeJG18~(b!5yywSqQiLAX0;---;}mF5&b4lg|T?LwKREa{9YX_<cWo
zp5tfV50Y2+lRda01HS}+=SxrfSkC!&*0gD>-zL@ZE?Zqi@HxK^2KO1>0LATu{te=T
zprmHtY)b<a2h{jY+qvO~gd4b2xl*<_GH{|zwlHuGaV{E&4NI!%G@mqwLs{g7HvMB%
z2s~ICsHlE``yt{1=`23o`-amH$$unpLE*NzEw=JdG?*<^m^k!pz>DVfxI1S}KBE7V
zznP7KQ8HekWU#W6mw`dr-boV}pMQR==&5=Q5T=_q091jfc;R*jX#&=MQ%~@E<Nx=l
z(`c9tr8XeeP)p+vFpRsF8+ykZgNmbi{a=<b0fAOdq6q+9!BQD=p-wQTT2lZ2F9|4N
z>@9^?`$v48ks<>(fI(F6L(5ppKy|$HWng*bKOb(4<vOk(wOcaY>|cMUB&z$#ob#XV
z5-mg)gmFIybZf=znm3ZPyUO^GJfxt0kmHjaTZ|sthsxXw&}Y)fOUSg=JhRSR^UjZ-
zhqqb}Wsyw4zdnj6@#BAJa#-PdI4_dgafFXh85DsEQ_cT+5)XpZq$fZlBA_9UsE9r6
zEFec5?uqN@QhJ^IzwZrwl-5J`CmVPv{(YDTqEqWR^dI;5hXc~cxP%B3v&~s0`Ct89
z@<j>S`i~a^c%V^N81dDT*ItFS*&IN;@O$EgzX0e7x&}TD=!zS}hTpezBLS>mdX(5<
z)8DEI(-o_D)c-UX@dA1<K6(L)RH684V}zX@mfT@j2yo`Ro-$w;wGyVdVefy{h%GPA
zH#;NsFn9h_JN!>MuJ*yc>Hf4|`*B2S_O>w*-tbUwtiu`;W(Ud{HTty@(&x(T(F&;M
zJ=?H>6`B7nf-90e8V`WSVp|0oEKB-P2M{}4ZDawzvM&a!y><z+0)0-#VZ)W0t8r%g
z-~|>`Y#jCsD%T_l``@ah(I2nJs~Q|%uSKu@k!m~*8B*IoA{*TgtF<(5sHC<erPY3+
zSLQ(IMXla;-GU6iB?UfZCeE{XNaL4(PjiART4+_2>GG;n@NE%~Xt(G$^&<87u;}Na
zx-8cq0g`uA(&RBFo=-4Y1GUZ<``Zw{xL4jfHkZw~%~wvtGueszcXt)_QwH8g!;<bu
zzrDuE#h)*{k%8~+kH8}$A~%^JC#N(Ma+3bg4{U~*3F15X@$%&#n@=lMg;&1P$Y(*p
z7yz6cl@9N$qh0i<_3Q`Mvz*F%U&8RLo2lH^EJQNlvIyu<LtY(`?-dE!ellYnpTJUt
zWyz(g4okY8bl$taIrAqM#f0F&K+q?$%Y#Bo_cK7?OG))(`m3;SG*Zm#V{-6Pa`Qi>
z%s&3kSa~R$dO$-%L-)c@_hi7&>{6L_M>OZFkUQu;{sL_bUMStNrt{{&O(Wn~*zPOk
zB>dnfszb29NSTf2pqIs68k|p-UrSrxgLHqi?3N-UFa!LHy9n1)=s>`y<fuaVPmb(~
zz)=<RXUQBIM}~iPJu#%Wwi2GAu&z6g$VGFj?X|^zB**;kyDt<U!9`MfEiOBYmGB2$
zG$~ieJM@n4{{1aq)sJLAo}_~^;5a83Mc&m?lkHqX)J*LsdvYPW`3=u!>S+J{MEzS@
zNlfGtpma7<xmFGQKk@0*S1C>kG&LR3JE@wB%rFA*h~~KitlO=IP)ZjN6dQLM6qsry
zHkB#cyNh#n`)}bCrN1My*;k)^@>e4gJ`LJK?2)Pwp?4Tl4)4FA0(tvY+#1jOUM)xw
zlMz4x-f@g^+yKUN`?Vu)|AwujArnM~Pa@y*Q9S8eS(u{-S%(Z5=R~pRl5ZGDjdqH%
zC8rW&{##wOpU_oTIG4WXMk4&%2t1;lWcW5&!yxmOT*!hBcKyTqEcNoO+R2;Q?Yj+W
z1-Y4?59fijz4(MIDwGe4-baYf08UCs;r|YefD-Md2ST;=cxwpgW=tR76-dQVAhn^=
zG9Wk5lQk%jIR@<yTWu!~7BSL}EaU!9*}jurfSr^gr3v}4SWo=qe_uir5ET_=zqVH?
z^-Xb+`s&KpVD!8H3<Q4JSU7a#fZOo-DNI6a7<D9Q7-76WTVHkoXw@Qa+I{cbs9u;g
zgaBs-6!44Xc>KNU!UMp6@BfU;r+;y4VQ)D2!Il9HX%yW-9nOzV+m$YKzVaO`B8S7t
z$!S2Mz`xw>V(RjE`0>bQp<0y&h~Y=M#jpy!#=dE>`=e_AjSZq6u!Dy1xJf~-7|0F!
zPR9|n`e_7D2DIV2H(CESQ}hA>U>n|6`%z?YKEA~)BOV<x=%f|d$^F24T5>Y%y=jPV
zT=44R!L?J)736X#csn|lfBJ)o8ixaZclguWgrGO<`TN2FMfO}7;5}d+BlK0yTSH3*
z4!=;5rOh85&2|x=46hkNaz?)U8&=bcfh=N_#8BNpZ2v$aVBo;sk^*X`v;4-LU;D>!
zM*h12MxXIQy)S<L)4A)~989;pH{VAzNJ*U*xdvrkCmWRHzJ<IQUTEo*%pzi~99ffl
z`b@Dw_H~K*;e505>fAqE4;jY)wgnppazZkdNNVVF;(PLf^qK$FgY9+VFyBKE7UC|f
z`R|?&egV11K3s$rJ6!GvoeW=jV*!-e(wA;x(2=d0E_e_%0x--0o8#~m^H1%AH5Z^B
zn!TNPn927*bvaf0pt}zhK0o^V@WlGwwKo(*nQ|Q~4_;>~-8y20`HP>@UJa)3nEnGG
z5Hwhs|FcmFG16ZVNb5hL`2Gc1{zWIMM{_OiKewV!hCi}U!VuE?s9wU-QbZ!)+Y^tS
zGzp5OSi5iq6hmEr$w}&9DFgoB+i*`q`8TBi^MVS{SKEb8Aw<u!+dlQv^<W`zFIS#6
zBX}^YZkb~Fa#p~~s@UZ{*GVonU8IKdl%^^)s%iX|S{D`{Q2x93h_^Y;4M@1`G+aRP
zY_Hfh>%@K7@XCo(De2A`6%mf&a2#~y1N)+kJLD<?ae}Pwz^G0<mc2h^x{@4W3a1c?
zJRUuiS4MZ22gBL^4>$1HCP!22)(U}xo2|j?WRzt(11j8Z_*v;P$R+Ug*Gy3VxV4K;
zGGUGabnW*`Z}~`ydXL-l9e=GC$pY#z|63vy>E*m=$=j}iWP{sRTh0%H54`t>2xYH%
zsk<hcZmDKwVGw47Y+}ICPKZ+sVU^F#Y1_%rPBL&#uKo@V4z9&DsQq__mbo#ve@m*0
zpZu|HoOkLk{c~MJ_%MH`ok|I_*@hQ+-x^aJAJ`sJ+a6HebkJ1KT%Sn$N`8pOcpBXm
zjiFmQCB=~odJEWfOI^UQMz6(pN`>+M&u&pNgMCM@3e)Xc?jBWX-TIR_cQ1Z!RW7!B
zBjZX=+^3}?SE)B+$EP+0oi1Fp5blDT?*}nsP>filqXH<uZhGh$jnxiIdJhq6e>{ms
zxU<$hetC`u)Wi+x|EKL-`y^#aQX+sDYIa{M;V%LqLrOk~lR>u0Q!+pyQSU4zY`?E^
z|5@)C)w6G_=i5YYC5SE_u(7hDNYr}uKT|@DSqF%S++lTIbIk^$a>{~0IH8KNFEy%+
zW#$&!ynpgNJh>6uR~?2c)ZMW+h0OKu231(7L_vETPaR+(P)Zy%0~yGm>E9?@@x!Jy
z3PYgS<yn;JHp>}Q@b}x}E#F27@F+j}0=&Ql4gES&f8acMrPAVlVs9$97`FR))R5wI
zc&}KFI1UIewh>3Pk<icV$Q}+{%jb)4^`l}mcOHYV{DOjw#*@;%)X2!lztrzyA^#aN
zynsufB*odZ9;cl30K_AD^!N5_m5XhE@5Xxl9uEVVKmNXq({KZBI#Elh=W_zug;<aR
z3MFdHei-!YBGDOyA{vm1?gqjM+r{yc_x4f$w{0#2p-;zX?BIw?xPGgLWB+7@-a`77
znH0H~2#9*meR%0<VCTbO#J{~Gv)OoB$Oz$gnW-xx%$_^^Bmu4*K8h;APQA)MSEWUO
zBD+oJ_rdp&$6XVKuF6Ro!cV%N`IBbr`3tr;%u?82*Q#q*E(I^O`H6vbS+;0>hnB7u
zS3AT8_*|nexznG|Z*DU0c!K@jsI4J)5#DyNi#|e#`l1Vv1`1)*NVcy0LZ``aL0n8B
zecupJ(rhq3u8bW0NIRhKYq$v1li+jp*4hfAd&wxYDE8<bDzN;1D!Q0|+DC@pvXFjH
z+a9cCCiifPr{y~K8S7coa^<1`y#o-P1d$O-4zEa6t%@l&7Jme#NDUn|dFwLJGr6~H
zl~YrJJcdBh`h=mtEU5FGZKK4^N(fCuH=`7}!^OJ!_(a*%DxN>vn1TQ7S@bTM|I2Ob
z8vMOIxA7&_j{AKmD+O@EyXT`|dElt0pED^@IV0m)RPBUs*5jW60>>w1!@_G3aBKzG
z_f(KfAPBk}-jQtR*Sroq!*3rbQ_m27e+YdzQjUb<_*k8vc_C)y!@cj5E>NxUhPu&g
z@Z2<~esU`)ih+4opWe+K7sbN9<br2kw6jeE($p-1;($sSX*XrS&B>n*9@n>#@n3*o
z?xoROgDuvhq>jJ;Ve{6i<3roQNfgo5^4Q4(|GNExO2Dr7GjgA2zWuKp_K)K0R(6lv
z!l$!zW-+T6mb3gQaAFviTQi{|*t%>{(mhTdy+y;Re4qT@kccy#{<kajvN^sBEw0gk
zN~nHi<%jBA&hG2Ecxre=v&^Ia{N-M0C<AuG+rGf<NNoH^0V~9s$@f(9sy1%?-nf!n
z$FS_0NEg6bDGXWr8=cI-`Ju|F6Zj<|E(4A~EFq|00n31`1M#x=7w<=|OI*$8MPJt0
z&(`&J&$W3xb0xnXKc2&naiQ`;pm-G6R-rkN2HDJhWI`ms^08YZeRnZFOo=LB?+f$)
zQ3&okk^dF!xYjKoe%yf~6`E{zFZYJ}KCf6A*a}*QKbYI<?b`=ZHzP8*oSrK|q~|>b
z&zWy~kLO@>*WPj2k#H)|7L&gAJ37DmHQAme#@m;(Y8Nu^`D5vf8sZFW#+lA2!HK=(
zJ)#hO6<Ki+wWwi}q))?H68AvN)n+zZXDRfDAt>JD*`o~&c*&46d}g=Qj@SsoB5ikC
z^1V8E+&<-OzuS_C`p5<<(A6fB`LXT(!kV^0_~hL6PpW4={l%|#xgdh?5EIk~lu8{D
z2hiyhv3Yxij_#$Wu>P@7SYsl`-~3;}Ktx{34_NL^Kwin&=?!HDv3elQDbcU*qyYpN
z(#yw~f1vFGK-t%CC-qa-4FYHbA^h>bag-I&*q<mz`em&&#tu{XKJz2@x7}hAxGwR#
zW_gLF54Fi?d7_5)Rk}~d%c_SM=XeBWK8YE_x9k-~-xL{UiqAz_icRQqwcuU=<bkH+
zKvFj>axwn?Qv|idE$<>1H|<n{Je}GVls}6m{%Y}l`3tUAcX+>Gr6JtUu(he2$eg!N
z@HTF@dG1)*y;4fxe)4_ZkpaBHH9hXp9p4|gLrRQyuevRd@gSS}JhRnWqrvm|U@>qM
z=yl7RQROTKwQtzP3!zUF)_6Ld#NGA6v~2{J9Dd`h6{%+XsU#qGLh%`fB1Hc?wfayK
zN`H4BpDp)npVQuu$DVW1qsBS&A<aRmfuB|Wf}Z=d<nZy_cK=9G@X}lpPGi~HuVZ)p
z!~jj37&JGox-2H6L(eFf_pRW0$w?z$%#VIih#Tu@LqCsd4!`5-A2d0P)&8#q&chOo
zJj{eq86wV`Ux6_3O&H75p@`mK|Izt*aY65@bvjVMEp3kD9mZ7UOttCXqdZb1yiBWN
zwgyl+Ug%HevPS^g(Q~FXjv~Rtb8AczqQ=iQG-i#IXG1^X_*?DQ${X&D3eGoN7JWTg
z8a7sYn8m~C8=CH=gAPauObRXw?k|Wy-Jqi_vj(1x@eP@~qA5-uR|VV;rFvoh_fgxZ
z2^SWfDIcfF?3u)O0ljr<*S_aP5#LCOGVxp$s9eX@|0+O@-?XM1*>J2eP<jM5Fuepp
zzNkv0Nl@M%tV|zme{2uMjXsFNjXL;NeM4nE^#egKS$6mKd{<A%W_pBL;y&uypQ{UL
z_uT7>%6Qw>;k{)Z$8%HL=Q4(a$Ng2_vHw&vA!1L+9zc8vaX2GtqJ{L-;gvF0IR$em
zMQ8@{Qp3+3Quk)TJ$?I<8KmwzD*7#(q<@Mc`dchngW}cRG14(Z6K7{<m7M5_m?K0B
zOrt~!%b9X9ad?n9>T|LhFXwhqUQ;BET;cYqPcAcMgt6M$V9$(?jHo@Sud$an$U&5F
zZ1QNh^ztt)E*d<a5>#Ij;<43oSKKnd+WNr$_r}+s_O_x6DZSB10*5Q{ourqq>mTl|
zx4y^(cy+9;t@R=*j>3_dmm_m)$k$#937V(sllby&5)Xex^UD-|m|q<(jEd#@DV(of
zAd7sSdmS*zUDqJ9|K%O2J<Hs(EGc*G)o85N*0CxtDC#y0UPN0Q?UvF{wo7g}@RjG&
zze`r3FoPtfZ_ysbFKDtX?-@T|<6L;xt>2OfdUiK{{b{PCy)pi<;hp~7v1CQj&4-10
zgO<3dqhYH1#-Fa}Q{pjql5>>P6gZH21zLfxZ4$SK4T@7b!|`nWF9b*84Bq8&Eht;9
z*P72x&NUCZ7*@B$`FtE=hz5b}S`<KDTyCibq&qt%zim@R!JaL<&GU0+1#{ZXuF6z)
zTH2{`eVL^@2H7lQwx^Tt(E@Vuwj*B-Oe&t~EO_>|c6Ey+j@D1ZibjJaRlR;{cxAWv
z?Nqa>QqV*H-*zzaPvpLMHt~nl(x6?vrPpR?zn7~wow?oj*1TKmx4j71>$hvtC$DLD
zUrz0^tiP0792U&dxJxNv@r}Elsjn^aSLUu=9#mD{&9n8|ayIL$!H3s>%KEvbchBFW
z%cd?VU83mGF#Dar9*s~w&AnmQRQIOvR+uWsuZ?+|a=TzApXO@q^(r%8=}iv#wCnFq
z=K9}JbqU@k99Q%j-}NNk+qLCP)jXfmOO|)@?mHcnynd6({mJisP1_}u7k)|eYHXWK
z63eQ)E$ufFi!3CWUY2gw%e>omCv}qEX66aH-k&35f9`Q@Us|NPetVqe8=dX*VxJdn
ze`q7b<f<?sU1f7>=Dn(UA(2sf&g)cOmQFhNJ#<-aMELJZbA#@to>25@kbW<)&!X01
z%NMJt>1ST)tyX)h@?`DxhbgCHr>S4wv}WC&Nw-!{+Z7$2D}74QAcXTvip=M0%Tp_N
zor=k`)t|ra^ySr-+(|R9mB(E=`MX#y(wSw)$!iymzB;^c*>%&^*7HxTnRga=soSZT
zdDl+9s;r!v8hk6POtzBaig4pRp7eWF(<8gufvNHPu6xs-=e{;mnHzJyGKE+8L0j};
z@%8-e^UCL5HhMiR>sD3Rve&yVZ#{Q1*CO8c+qSr^Z#CN;)(X5>tGG5yUw3<+CfhaL
z%bP;hZ?jvgJU67BWyiy74_)6r)_nSxttxn0`0?HE^5(uydHVgP+HE$V?Lv)Leti43
zWA|;f-RqX``95>)^P-fw!Vi{3KNsII-*5f){gdxqd%gVdB1sOBNe=nEW%;i~g_P8J
w!5uhoe-Jcg1nPN%MiEAtgE$;km@@t6ukO)1^!cY^83Pb_y85}Sb4q9e0FIsP9{>OV

literal 0
HcmV?d00001

diff --git a/frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/frontend/app/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
new file mode 100644
index 0000000000000000000000000000000000000000..2f1632cfddf3d9dade342351e627a0a75609fb46
GIT binary patch
literal 2218
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

literal 0
HcmV?d00001

diff --git a/frontend/app/macos/Runner/Base.lproj/MainMenu.xib b/frontend/app/macos/Runner/Base.lproj/MainMenu.xib
new file mode 100644
index 0000000..80e867a
--- /dev/null
+++ b/frontend/app/macos/Runner/Base.lproj/MainMenu.xib
@@ -0,0 +1,343 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
+    <dependencies>
+        <deployment identifier="macosx"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
+            <connections>
+                <outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
+            </connections>
+        </customObject>
+        <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
+        <customObject id="-3" userLabel="Application" customClass="NSObject"/>
+        <customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Runner" customModuleProvider="target">
+            <connections>
+                <outlet property="applicationMenu" destination="uQy-DD-JDr" id="XBo-yE-nKs"/>
+                <outlet property="mainFlutterWindow" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
+            </connections>
+        </customObject>
+        <customObject id="YLy-65-1bz" customClass="NSFontManager"/>
+        <menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
+            <items>
+                <menuItem title="APP_NAME" id="1Xt-HY-uBw">
+                    <modifierMask key="keyEquivalentModifierMask"/>
+                    <menu key="submenu" title="APP_NAME" systemMenu="apple" id="uQy-DD-JDr">
+                        <items>
+                            <menuItem title="About APP_NAME" id="5kV-Vb-QxS">
+                                <modifierMask key="keyEquivalentModifierMask"/>
+                                <connections>
+                                    <action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
+                                </connections>
+                            </menuItem>
+                            <menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
+                            <menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
+                            <menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
+                            <menuItem title="Services" id="NMo-om-nkz">
+                                <modifierMask key="keyEquivalentModifierMask"/>
+                                <menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
+                            </menuItem>
+                            <menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
+                            <menuItem title="Hide APP_NAME" keyEquivalent="h" id="Olw-nP-bQN">
+                                <connections>
+                                    <action selector="hide:" target="-1" id="PnN-Uc-m68"/>
+                                </connections>
+                            </menuItem>
+                            <menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
+                                <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+                                <connections>
+                                    <action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
+                                </connections>
+                            </menuItem>
+                            <menuItem title="Show All" id="Kd2-mp-pUS">
+                                <modifierMask key="keyEquivalentModifierMask"/>
+                                <connections>
+                                    <action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
+                                </connections>
+                            </menuItem>
+                            <menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
+                            <menuItem title="Quit APP_NAME" keyEquivalent="q" id="4sb-4s-VLi">
+                                <connections>
+                                    <action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
+                                </connections>
+                            </menuItem>
+                        </items>
+                    </menu>
+                </menuItem>
+                <menuItem title="Edit" id="5QF-Oa-p0T">
+                    <modifierMask key="keyEquivalentModifierMask"/>
+                    <menu key="submenu" title="Edit" id="W48-6f-4Dl">
+                        <items>
+                            <menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
+                                <connections>
+                                    <action selector="undo:" target="-1" id="M6e-cu-g7V"/>
+                                </connections>
+                            </menuItem>
+                            <menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
+                                <connections>
+                                    <action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
+                                </connections>
+                            </menuItem>
+                            <menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
+                            <menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
+                                <connections>
+                                    <action selector="cut:" target="-1" id="YJe-68-I9s"/>
+                                </connections>
+                            </menuItem>
+                            <menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
+                                <connections>
+                                    <action selector="copy:" target="-1" id="G1f-GL-Joy"/>
+                                </connections>
+                            </menuItem>
+                            <menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
+                                <connections>
+                                    <action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
+                                </connections>
+                            </menuItem>
+                            <menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
+                                <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+                                <connections>
+                                    <action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
+                                </connections>
+                            </menuItem>
+                            <menuItem title="Delete" id="pa3-QI-u2k">
+                                <modifierMask key="keyEquivalentModifierMask"/>
+                                <connections>
+                                    <action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
+                                </connections>
+                            </menuItem>
+                            <menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
+                                <connections>
+                                    <action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
+                                </connections>
+                            </menuItem>
+                            <menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
+                            <menuItem title="Find" id="4EN-yA-p0u">
+                                <modifierMask key="keyEquivalentModifierMask"/>
+                                <menu key="submenu" title="Find" id="1b7-l0-nxx">
+                                    <items>
+                                        <menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
+                                            <connections>
+                                                <action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
+                                            <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+                                            <connections>
+                                                <action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
+                                            <connections>
+                                                <action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
+                                            <connections>
+                                                <action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
+                                            <connections>
+                                                <action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
+                                            <connections>
+                                                <action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
+                                            </connections>
+                                        </menuItem>
+                                    </items>
+                                </menu>
+                            </menuItem>
+                            <menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
+                                <modifierMask key="keyEquivalentModifierMask"/>
+                                <menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
+                                    <items>
+                                        <menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
+                                            <connections>
+                                                <action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
+                                            <connections>
+                                                <action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
+                                        <menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
+                                            </connections>
+                                        </menuItem>
+                                    </items>
+                                </menu>
+                            </menuItem>
+                            <menuItem title="Substitutions" id="9ic-FL-obx">
+                                <modifierMask key="keyEquivalentModifierMask"/>
+                                <menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
+                                    <items>
+                                        <menuItem title="Show Substitutions" id="z6F-FW-3nz">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
+                                        <menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Smart Quotes" id="hQb-2v-fYv">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Smart Dashes" id="rgM-f4-ycn">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Smart Links" id="cwL-P1-jid">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Data Detectors" id="tRr-pd-1PS">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Text Replacement" id="HFQ-gK-NFA">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
+                                            </connections>
+                                        </menuItem>
+                                    </items>
+                                </menu>
+                            </menuItem>
+                            <menuItem title="Transformations" id="2oI-Rn-ZJC">
+                                <modifierMask key="keyEquivalentModifierMask"/>
+                                <menu key="submenu" title="Transformations" id="c8a-y6-VQd">
+                                    <items>
+                                        <menuItem title="Make Upper Case" id="vmV-6d-7jI">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Make Lower Case" id="d9M-CD-aMd">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Capitalize" id="UEZ-Bs-lqG">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
+                                            </connections>
+                                        </menuItem>
+                                    </items>
+                                </menu>
+                            </menuItem>
+                            <menuItem title="Speech" id="xrE-MZ-jX0">
+                                <modifierMask key="keyEquivalentModifierMask"/>
+                                <menu key="submenu" title="Speech" id="3rS-ZA-NoH">
+                                    <items>
+                                        <menuItem title="Start Speaking" id="Ynk-f8-cLZ">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Stop Speaking" id="Oyz-dy-DGm">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
+                                            </connections>
+                                        </menuItem>
+                                    </items>
+                                </menu>
+                            </menuItem>
+                        </items>
+                    </menu>
+                </menuItem>
+                <menuItem title="View" id="H8h-7b-M4v">
+                    <modifierMask key="keyEquivalentModifierMask"/>
+                    <menu key="submenu" title="View" id="HyV-fh-RgO">
+                        <items>
+                            <menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
+                                <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
+                                <connections>
+                                    <action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/>
+                                </connections>
+                            </menuItem>
+                        </items>
+                    </menu>
+                </menuItem>
+                <menuItem title="Window" id="aUF-d1-5bR">
+                    <modifierMask key="keyEquivalentModifierMask"/>
+                    <menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
+                        <items>
+                            <menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
+                                <connections>
+                                    <action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
+                                </connections>
+                            </menuItem>
+                            <menuItem title="Zoom" id="R4o-n2-Eq4">
+                                <modifierMask key="keyEquivalentModifierMask"/>
+                                <connections>
+                                    <action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
+                                </connections>
+                            </menuItem>
+                            <menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
+                            <menuItem title="Bring All to Front" id="LE2-aR-0XJ">
+                                <modifierMask key="keyEquivalentModifierMask"/>
+                                <connections>
+                                    <action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
+                                </connections>
+                            </menuItem>
+                        </items>
+                    </menu>
+                </menuItem>
+                <menuItem title="Help" id="EPT-qC-fAb">
+                    <modifierMask key="keyEquivalentModifierMask"/>
+                    <menu key="submenu" title="Help" systemMenu="help" id="rJ0-wn-3NY"/>
+                </menuItem>
+            </items>
+            <point key="canvasLocation" x="142" y="-258"/>
+        </menu>
+        <window title="APP_NAME" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="MainFlutterWindow" customModule="Runner" customModuleProvider="target">
+            <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
+            <rect key="contentRect" x="335" y="390" width="800" height="600"/>
+            <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1577"/>
+            <view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
+                <rect key="frame" x="0.0" y="0.0" width="800" height="600"/>
+                <autoresizingMask key="autoresizingMask"/>
+            </view>
+        </window>
+    </objects>
+</document>
diff --git a/frontend/app/macos/Runner/Configs/AppInfo.xcconfig b/frontend/app/macos/Runner/Configs/AppInfo.xcconfig
new file mode 100644
index 0000000..e7b0850
--- /dev/null
+++ b/frontend/app/macos/Runner/Configs/AppInfo.xcconfig
@@ -0,0 +1,14 @@
+// Application-level settings for the Runner target.
+//
+// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
+// future. If not, the values below would default to using the project name when this becomes a
+// 'flutter create' template.
+
+// The application's name. By default this is also the title of the Flutter window.
+PRODUCT_NAME = app
+
+// The application's bundle identifier
+PRODUCT_BUNDLE_IDENTIFIER = com.example.app
+
+// The copyright displayed in application information
+PRODUCT_COPYRIGHT = Copyright © 2023 com.example. All rights reserved.
diff --git a/frontend/app/macos/Runner/Configs/Debug.xcconfig b/frontend/app/macos/Runner/Configs/Debug.xcconfig
new file mode 100644
index 0000000..36b0fd9
--- /dev/null
+++ b/frontend/app/macos/Runner/Configs/Debug.xcconfig
@@ -0,0 +1,2 @@
+#include "../../Flutter/Flutter-Debug.xcconfig"
+#include "Warnings.xcconfig"
diff --git a/frontend/app/macos/Runner/Configs/Release.xcconfig b/frontend/app/macos/Runner/Configs/Release.xcconfig
new file mode 100644
index 0000000..dff4f49
--- /dev/null
+++ b/frontend/app/macos/Runner/Configs/Release.xcconfig
@@ -0,0 +1,2 @@
+#include "../../Flutter/Flutter-Release.xcconfig"
+#include "Warnings.xcconfig"
diff --git a/frontend/app/macos/Runner/Configs/Warnings.xcconfig b/frontend/app/macos/Runner/Configs/Warnings.xcconfig
new file mode 100644
index 0000000..42bcbf4
--- /dev/null
+++ b/frontend/app/macos/Runner/Configs/Warnings.xcconfig
@@ -0,0 +1,13 @@
+WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
+GCC_WARN_UNDECLARED_SELECTOR = YES
+CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
+CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
+CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
+CLANG_WARN_PRAGMA_PACK = YES
+CLANG_WARN_STRICT_PROTOTYPES = YES
+CLANG_WARN_COMMA = YES
+GCC_WARN_STRICT_SELECTOR_MATCH = YES
+CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
+CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
+GCC_WARN_SHADOW = YES
+CLANG_WARN_UNREACHABLE_CODE = YES
diff --git a/frontend/app/macos/Runner/DebugProfile.entitlements b/frontend/app/macos/Runner/DebugProfile.entitlements
new file mode 100644
index 0000000..dddb8a3
--- /dev/null
+++ b/frontend/app/macos/Runner/DebugProfile.entitlements
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>com.apple.security.app-sandbox</key>
+	<true/>
+	<key>com.apple.security.cs.allow-jit</key>
+	<true/>
+	<key>com.apple.security.network.server</key>
+	<true/>
+</dict>
+</plist>
diff --git a/frontend/app/macos/Runner/Info.plist b/frontend/app/macos/Runner/Info.plist
new file mode 100644
index 0000000..4789daa
--- /dev/null
+++ b/frontend/app/macos/Runner/Info.plist
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>$(DEVELOPMENT_LANGUAGE)</string>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIconFile</key>
+	<string></string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>$(FLUTTER_BUILD_NAME)</string>
+	<key>CFBundleVersion</key>
+	<string>$(FLUTTER_BUILD_NUMBER)</string>
+	<key>LSMinimumSystemVersion</key>
+	<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
+	<key>NSHumanReadableCopyright</key>
+	<string>$(PRODUCT_COPYRIGHT)</string>
+	<key>NSMainNibFile</key>
+	<string>MainMenu</string>
+	<key>NSPrincipalClass</key>
+	<string>NSApplication</string>
+</dict>
+</plist>
diff --git a/frontend/app/macos/Runner/MainFlutterWindow.swift b/frontend/app/macos/Runner/MainFlutterWindow.swift
new file mode 100644
index 0000000..3cc05eb
--- /dev/null
+++ b/frontend/app/macos/Runner/MainFlutterWindow.swift
@@ -0,0 +1,15 @@
+import Cocoa
+import FlutterMacOS
+
+class MainFlutterWindow: NSWindow {
+  override func awakeFromNib() {
+    let flutterViewController = FlutterViewController()
+    let windowFrame = self.frame
+    self.contentViewController = flutterViewController
+    self.setFrame(windowFrame, display: true)
+
+    RegisterGeneratedPlugins(registry: flutterViewController)
+
+    super.awakeFromNib()
+  }
+}
diff --git a/frontend/app/macos/Runner/Release.entitlements b/frontend/app/macos/Runner/Release.entitlements
new file mode 100644
index 0000000..852fa1a
--- /dev/null
+++ b/frontend/app/macos/Runner/Release.entitlements
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>com.apple.security.app-sandbox</key>
+	<true/>
+</dict>
+</plist>
diff --git a/frontend/app/macos/RunnerTests/RunnerTests.swift b/frontend/app/macos/RunnerTests/RunnerTests.swift
new file mode 100644
index 0000000..5418c9f
--- /dev/null
+++ b/frontend/app/macos/RunnerTests/RunnerTests.swift
@@ -0,0 +1,12 @@
+import FlutterMacOS
+import Cocoa
+import XCTest
+
+class RunnerTests: XCTestCase {
+
+  func testExample() {
+    // If you add code to the Runner application, consider adding tests here.
+    // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
+  }
+
+}
diff --git a/frontend/app/pubspec.lock b/frontend/app/pubspec.lock
new file mode 100644
index 0000000..687c22e
--- /dev/null
+++ b/frontend/app/pubspec.lock
@@ -0,0 +1,300 @@
+# Generated by pub
+# See https://dart.dev/tools/pub/glossary#lockfile
+packages:
+  archive:
+    dependency: transitive
+    description:
+      name: archive
+      sha256: "7e0d52067d05f2e0324268097ba723b71cb41ac8a6a2b24d1edf9c536b987b03"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.4.6"
+  args:
+    dependency: transitive
+    description:
+      name: args
+      sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.4.2"
+  async:
+    dependency: "direct main"
+    description:
+      name: async
+      sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.11.0"
+  boolean_selector:
+    dependency: transitive
+    description:
+      name: boolean_selector
+      sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.1"
+  characters:
+    dependency: transitive
+    description:
+      name: characters
+      sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.3.0"
+  clock:
+    dependency: transitive
+    description:
+      name: clock
+      sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.1.1"
+  collection:
+    dependency: "direct main"
+    description:
+      name: collection
+      sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.17.2"
+  convert:
+    dependency: transitive
+    description:
+      name: convert
+      sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.1.1"
+  crypto:
+    dependency: transitive
+    description:
+      name: crypto
+      sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.3"
+  cupertino_icons:
+    dependency: "direct main"
+    description:
+      name: cupertino_icons
+      sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.6"
+  fake_async:
+    dependency: transitive
+    description:
+      name: fake_async
+      sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.3.1"
+  fixnum:
+    dependency: transitive
+    description:
+      name: fixnum
+      sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.1.0"
+  flutter:
+    dependency: "direct main"
+    description: flutter
+    source: sdk
+    version: "0.0.0"
+  flutter_lints:
+    dependency: "direct dev"
+    description:
+      name: flutter_lints
+      sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.0.3"
+  flutter_test:
+    dependency: "direct dev"
+    description: flutter
+    source: sdk
+    version: "0.0.0"
+  googleapis_auth:
+    dependency: transitive
+    description:
+      name: googleapis_auth
+      sha256: af7c3a3edf9d0de2e1e0a77e994fae0a581c525fa7012af4fa0d4a52ed9484da
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.4.1"
+  grpc:
+    dependency: "direct main"
+    description:
+      name: grpc
+      sha256: e93ee3bce45c134bf44e9728119102358c7cd69de7832d9a874e2e74eb8cab40
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.2.4"
+  http:
+    dependency: transitive
+    description:
+      name: http
+      sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.1.0"
+  http2:
+    dependency: transitive
+    description:
+      name: http2
+      sha256: "38db0c4aa9f1cd238a5d2e86aa0cc7cc91c77e0c6c94ba64bbe85e4ff732a952"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.0"
+  http_parser:
+    dependency: transitive
+    description:
+      name: http_parser
+      sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
+      url: "https://pub.dev"
+    source: hosted
+    version: "4.0.2"
+  js:
+    dependency: transitive
+    description:
+      name: js
+      sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.6.7"
+  lints:
+    dependency: "direct dev"
+    description:
+      name: lints
+      sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.1"
+  matcher:
+    dependency: transitive
+    description:
+      name: matcher
+      sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.12.16"
+  material_color_utilities:
+    dependency: transitive
+    description:
+      name: material_color_utilities
+      sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.5.0"
+  meta:
+    dependency: transitive
+    description:
+      name: meta
+      sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.9.1"
+  path:
+    dependency: transitive
+    description:
+      name: path
+      sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.8.3"
+  pointycastle:
+    dependency: transitive
+    description:
+      name: pointycastle
+      sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.7.3"
+  protobuf:
+    dependency: "direct main"
+    description:
+      name: protobuf
+      sha256: "68645b24e0716782e58948f8467fd42a880f255096a821f9e7d0ec625b00c84d"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.1.0"
+  sky_engine:
+    dependency: transitive
+    description: flutter
+    source: sdk
+    version: "0.0.99"
+  source_span:
+    dependency: transitive
+    description:
+      name: source_span
+      sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.10.0"
+  stack_trace:
+    dependency: transitive
+    description:
+      name: stack_trace
+      sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.11.0"
+  stream_channel:
+    dependency: transitive
+    description:
+      name: stream_channel
+      sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.1"
+  string_scanner:
+    dependency: transitive
+    description:
+      name: string_scanner
+      sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.2.0"
+  term_glyph:
+    dependency: transitive
+    description:
+      name: term_glyph
+      sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.2.1"
+  test_api:
+    dependency: transitive
+    description:
+      name: test_api
+      sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.6.0"
+  typed_data:
+    dependency: transitive
+    description:
+      name: typed_data
+      sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.3.2"
+  vector_math:
+    dependency: transitive
+    description:
+      name: vector_math
+      sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.4"
+  web:
+    dependency: transitive
+    description:
+      name: web
+      sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.1.4-beta"
+sdks:
+  dart: ">=3.1.4 <4.0.0"
diff --git a/frontend/app/pubspec.yaml b/frontend/app/pubspec.yaml
new file mode 100644
index 0000000..0372b7a
--- /dev/null
+++ b/frontend/app/pubspec.yaml
@@ -0,0 +1,95 @@
+name: app
+description: App for df
+# The following line prevents the package from being accidentally published to
+# pub.dev using `flutter pub publish`. This is preferred for private packages.
+publish_to: 'none' # Remove this line if you wish to publish to pub.dev
+
+# The following defines the version and build number for your application.
+# A version number is three numbers separated by dots, like 1.2.43
+# followed by an optional build number separated by a +.
+# Both the version and the builder number may be overridden in flutter
+# build by specifying --build-name and --build-number, respectively.
+# In Android, build-name is used as versionName while build-number used as versionCode.
+# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
+# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
+# Read more about iOS versioning at
+# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
+# In Windows, build-name is used as the major, minor, and patch parts
+# of the product and file versions while build-number is used as the build suffix.
+version: 1.0.0+1
+
+environment:
+  sdk: '>=3.1.4 <4.0.0'
+
+# Dependencies specify other packages that your package needs in order to work.
+# To automatically upgrade your package dependencies to the latest versions
+# consider running `flutter pub upgrade --major-versions`. Alternatively,
+# dependencies can be manually updated by changing the version numbers below to
+# the latest version available on pub.dev. To see which dependencies have newer
+# versions available, run `flutter pub outdated`.
+dependencies:
+  async: ^2.2.0
+  protobuf: ^3.0.0
+  collection: ^1.15.0-nullsafety.4
+  flutter:
+    sdk: flutter
+
+
+  # The following adds the Cupertino Icons font to your application.
+  # Use with the CupertinoIcons class for iOS style icons.
+  cupertino_icons: ^1.0.2
+  grpc: ^3.2.4
+
+dev_dependencies:
+  lints: ^2.0.0
+  flutter_test:
+    sdk: flutter
+
+  # The "flutter_lints" package below contains a set of recommended lints to
+  # encourage good coding practices. The lint set provided by the package is
+  # activated in the `analysis_options.yaml` file located at the root of your
+  # package. See that file for information about deactivating specific lint
+  # rules and activating additional ones.
+  flutter_lints: ^2.0.0
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+
+# The following section is specific to Flutter packages.
+flutter:
+
+  # The following line ensures that the Material Icons font is
+  # included with your application, so that you can use the icons in
+  # the material Icons class.
+  uses-material-design: true
+
+  # To add assets to your application, add an assets section, like this:
+  # assets:
+  #   - images/a_dot_burr.jpeg
+  #   - images/a_dot_ham.jpeg
+
+  # An image asset can refer to one or more resolution-specific "variants", see
+  # https://flutter.dev/assets-and-images/#resolution-aware
+
+  # For details regarding adding assets from package dependencies, see
+  # https://flutter.dev/assets-and-images/#from-packages
+
+  # To add custom fonts to your application, add a fonts section here,
+  # in this "flutter" section. Each entry in this list should have a
+  # "family" key with the font family name, and a "fonts" key with a
+  # list giving the asset and other descriptors for the font. For
+  # example:
+  # fonts:
+  #   - family: Schyler
+  #     fonts:
+  #       - asset: fonts/Schyler-Regular.ttf
+  #       - asset: fonts/Schyler-Italic.ttf
+  #         style: italic
+  #   - family: Trajan Pro
+  #     fonts:
+  #       - asset: fonts/TrajanPro.ttf
+  #       - asset: fonts/TrajanPro_Bold.ttf
+  #         weight: 700
+  #
+  # For details regarding fonts from package dependencies,
+  # see https://flutter.dev/custom-fonts/#from-packages
diff --git a/frontend/app/web/favicon.png b/frontend/app/web/favicon.png
new file mode 100644
index 0000000000000000000000000000000000000000..8aaa46ac1ae21512746f852a42ba87e4165dfdd1
GIT binary patch
literal 917
zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|I14-?iy0X7
zltGxWVyS%@P(fs7NJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8ErclUHn2
zVXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l<c?^6clWVQqrt~T->1AfjnEK
zjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf|i<65o
z3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp$>4P^%3{)XKjo
zGZknv$b36P8?Z_gF{nK@`XI}Z90TzwSQO}0J1!f2c(B=V`5aP@1P1a|PZ!4!3&Gl8
zTYqUsf!gYFyJnXpu0!n&N*<mM6;!yDy;iI!?0xZxS-@9o){@>SYAX-%d(5<QWisP%
zpKxJ^!zO{CB{zx^b({)M+}nHh%-rj7^M&&ZcU$j%zjx;LVyDXoIuhq|8P;5s=KHG5
z<JUB4<A0$RmNJizixz(PY{v3_`K1HjE{oV$3+pLbhDf-dGF^GSkNIsaZ^^?aj@RFX
zmI#!cuT=hV*<Wg+koNS~T)(gK8EvWbJGDN%Cgswi@;rmS$PYP}{^d1_2Ol_C#PhDD
zFw$(<^hU$>gVjrHJWqXQshj@!<B9Fv+a9JEO;0$m^uEygb*U`#RIBf=|21JrRHoLF
zSVqsI&*oWt$jm+Fz?pMwCX>Zm{!01WsQrH~9=kTxW#6SvuapgMqt>$=j#%eyGrQzr
zP{L-3gsMA^$I1&gsBAEL+vxi1*Igl=8#8`5?A-T5=z-sk46WA1IUT)AIZHx1rdUrf
zVJrJn<74DDw`j)Ki#gt}mIT-Q`XRa2-jQXQoI%w`nb|XblvzK${ZzlV)m-XcwC(od
z71_OEC5Bt9GEXosOXaPTYOia#R4ID2TiU~`zVMl08TV_C%DnU4^+HE>9(CE4D6?Fz
oujB08i7adh9xk7*FX66dWH6F5TM;?E2b5PlUHx3vIVCg!0Dx9vYXATM

literal 0
HcmV?d00001

diff --git a/frontend/app/web/icons/Icon-192.png b/frontend/app/web/icons/Icon-192.png
new file mode 100644
index 0000000000000000000000000000000000000000..b749bfef07473333cf1dd31e9eed89862a5d52aa
GIT binary patch
literal 5292
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

literal 0
HcmV?d00001

diff --git a/frontend/app/web/icons/Icon-512.png b/frontend/app/web/icons/Icon-512.png
new file mode 100644
index 0000000000000000000000000000000000000000..88cfd48dff1169879ba46840804b412fe02fefd6
GIT binary patch
literal 8252
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

literal 0
HcmV?d00001

diff --git a/frontend/app/web/icons/Icon-maskable-192.png b/frontend/app/web/icons/Icon-maskable-192.png
new file mode 100644
index 0000000000000000000000000000000000000000..eb9b4d76e525556d5d89141648c724331630325d
GIT binary patch
literal 5594
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
X>c!)3PgKfL&lX^$Z>Cpu&6)6jvi^Z!

literal 0
HcmV?d00001

diff --git a/frontend/app/web/icons/Icon-maskable-512.png b/frontend/app/web/icons/Icon-maskable-512.png
new file mode 100644
index 0000000000000000000000000000000000000000..d69c56691fbdb0b7efa65097c7cc1edac12a6d3e
GIT binary patch
literal 20998
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
MPgg&ebxsLQ025IeI{*Lx

literal 0
HcmV?d00001

diff --git a/frontend/app/web/index.html b/frontend/app/web/index.html
new file mode 100644
index 0000000..fd44481
--- /dev/null
+++ b/frontend/app/web/index.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <!--
+    If you are serving your web app in a path other than the root, change the
+    href value below to reflect the base path you are serving from.
+
+    The path provided below has to start and end with a slash "/" in order for
+    it to work correctly.
+
+    For more details:
+    * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
+
+    This is a placeholder for base href that will be replaced by the value of
+    the `--base-href` argument provided to `flutter build`.
+  -->
+  <base href="$FLUTTER_BASE_HREF">
+
+  <meta charset="UTF-8">
+  <meta content="IE=Edge" http-equiv="X-UA-Compatible">
+  <meta name="description" content="A new Flutter project.">
+
+  <!-- iOS meta tags & icons -->
+  <meta name="apple-mobile-web-app-capable" content="yes">
+  <meta name="apple-mobile-web-app-status-bar-style" content="black">
+  <meta name="apple-mobile-web-app-title" content="app">
+  <link rel="apple-touch-icon" href="icons/Icon-192.png">
+
+  <!-- Favicon -->
+  <link rel="icon" type="image/png" href="favicon.png"/>
+
+  <title>app</title>
+  <link rel="manifest" href="manifest.json">
+
+  <script>
+    // The value below is injected by flutter build, do not touch.
+    const serviceWorkerVersion = null;
+  </script>
+  <!-- This script adds the flutter initialization JS code -->
+  <script src="flutter.js" defer></script>
+</head>
+<body>
+  <script>
+    window.addEventListener('load', function(ev) {
+      // Download main.dart.js
+      _flutter.loader.loadEntrypoint({
+        serviceWorker: {
+          serviceWorkerVersion: serviceWorkerVersion,
+        },
+        onEntrypointLoaded: function(engineInitializer) {
+          engineInitializer.initializeEngine().then(function(appRunner) {
+            appRunner.runApp();
+          });
+        }
+      });
+    });
+  </script>
+</body>
+</html>
diff --git a/frontend/app/web/manifest.json b/frontend/app/web/manifest.json
new file mode 100644
index 0000000..5620a33
--- /dev/null
+++ b/frontend/app/web/manifest.json
@@ -0,0 +1,35 @@
+{
+    "name": "app",
+    "short_name": "app",
+    "start_url": ".",
+    "display": "standalone",
+    "background_color": "#0175C2",
+    "theme_color": "#0175C2",
+    "description": "A new Flutter project.",
+    "orientation": "portrait-primary",
+    "prefer_related_applications": false,
+    "icons": [
+        {
+            "src": "icons/Icon-192.png",
+            "sizes": "192x192",
+            "type": "image/png"
+        },
+        {
+            "src": "icons/Icon-512.png",
+            "sizes": "512x512",
+            "type": "image/png"
+        },
+        {
+            "src": "icons/Icon-maskable-192.png",
+            "sizes": "192x192",
+            "type": "image/png",
+            "purpose": "maskable"
+        },
+        {
+            "src": "icons/Icon-maskable-512.png",
+            "sizes": "512x512",
+            "type": "image/png",
+            "purpose": "maskable"
+        }
+    ]
+}
diff --git a/frontend/app/windows/.gitignore b/frontend/app/windows/.gitignore
new file mode 100644
index 0000000..d492d0d
--- /dev/null
+++ b/frontend/app/windows/.gitignore
@@ -0,0 +1,17 @@
+flutter/ephemeral/
+
+# Visual Studio user-specific files.
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# Visual Studio build-related files.
+x64/
+x86/
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
diff --git a/frontend/app/windows/CMakeLists.txt b/frontend/app/windows/CMakeLists.txt
new file mode 100644
index 0000000..db76f0d
--- /dev/null
+++ b/frontend/app/windows/CMakeLists.txt
@@ -0,0 +1,102 @@
+# Project-level configuration.
+cmake_minimum_required(VERSION 3.14)
+project(app LANGUAGES CXX)
+
+# The name of the executable created for the application. Change this to change
+# the on-disk name of your application.
+set(BINARY_NAME "app")
+
+# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
+# versions of CMake.
+cmake_policy(VERSION 3.14...3.25)
+
+# Define build configuration option.
+get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(IS_MULTICONFIG)
+  set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
+    CACHE STRING "" FORCE)
+else()
+  if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
+    set(CMAKE_BUILD_TYPE "Debug" CACHE
+      STRING "Flutter build mode" FORCE)
+    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
+      "Debug" "Profile" "Release")
+  endif()
+endif()
+# Define settings for the Profile build mode.
+set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
+set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
+set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
+set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
+
+# Use Unicode for all projects.
+add_definitions(-DUNICODE -D_UNICODE)
+
+# Compilation settings that should be applied to most targets.
+#
+# Be cautious about adding new options here, as plugins use this function by
+# default. In most cases, you should add new options to specific targets instead
+# of modifying this function.
+function(APPLY_STANDARD_SETTINGS TARGET)
+  target_compile_features(${TARGET} PUBLIC cxx_std_17)
+  target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
+  target_compile_options(${TARGET} PRIVATE /EHsc)
+  target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
+  target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>")
+endfunction()
+
+# Flutter library and tool build rules.
+set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
+add_subdirectory(${FLUTTER_MANAGED_DIR})
+
+# Application build; see runner/CMakeLists.txt.
+add_subdirectory("runner")
+
+
+# Generated plugin build rules, which manage building the plugins and adding
+# them to the application.
+include(flutter/generated_plugins.cmake)
+
+
+# === Installation ===
+# Support files are copied into place next to the executable, so that it can
+# run in place. This is done instead of making a separate bundle (as on Linux)
+# so that building and running from within Visual Studio will work.
+set(BUILD_BUNDLE_DIR "$<TARGET_FILE_DIR:${BINARY_NAME}>")
+# Make the "install" step default, as it's required to run.
+set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
+if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
+  set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
+endif()
+
+set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
+set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
+
+install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
+  COMPONENT Runtime)
+
+install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
+  COMPONENT Runtime)
+
+install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
+  COMPONENT Runtime)
+
+if(PLUGIN_BUNDLED_LIBRARIES)
+  install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
+    DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
+    COMPONENT Runtime)
+endif()
+
+# Fully re-copy the assets directory on each build to avoid having stale files
+# from a previous install.
+set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
+install(CODE "
+  file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
+  " COMPONENT Runtime)
+install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
+  DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
+
+# Install the AOT library on non-Debug builds only.
+install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
+  CONFIGURATIONS Profile;Release
+  COMPONENT Runtime)
diff --git a/frontend/app/windows/flutter/CMakeLists.txt b/frontend/app/windows/flutter/CMakeLists.txt
new file mode 100644
index 0000000..930d207
--- /dev/null
+++ b/frontend/app/windows/flutter/CMakeLists.txt
@@ -0,0 +1,104 @@
+# This file controls Flutter-level build steps. It should not be edited.
+cmake_minimum_required(VERSION 3.14)
+
+set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
+
+# Configuration provided via flutter tool.
+include(${EPHEMERAL_DIR}/generated_config.cmake)
+
+# TODO: Move the rest of this into files in ephemeral. See
+# https://github.com/flutter/flutter/issues/57146.
+set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
+
+# === Flutter Library ===
+set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
+
+# Published to parent scope for install step.
+set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
+set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
+set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
+set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE)
+
+list(APPEND FLUTTER_LIBRARY_HEADERS
+  "flutter_export.h"
+  "flutter_windows.h"
+  "flutter_messenger.h"
+  "flutter_plugin_registrar.h"
+  "flutter_texture_registrar.h"
+)
+list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/")
+add_library(flutter INTERFACE)
+target_include_directories(flutter INTERFACE
+  "${EPHEMERAL_DIR}"
+)
+target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib")
+add_dependencies(flutter flutter_assemble)
+
+# === Wrapper ===
+list(APPEND CPP_WRAPPER_SOURCES_CORE
+  "core_implementations.cc"
+  "standard_codec.cc"
+)
+list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
+list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
+  "plugin_registrar.cc"
+)
+list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
+list(APPEND CPP_WRAPPER_SOURCES_APP
+  "flutter_engine.cc"
+  "flutter_view_controller.cc"
+)
+list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
+
+# Wrapper sources needed for a plugin.
+add_library(flutter_wrapper_plugin STATIC
+  ${CPP_WRAPPER_SOURCES_CORE}
+  ${CPP_WRAPPER_SOURCES_PLUGIN}
+)
+apply_standard_settings(flutter_wrapper_plugin)
+set_target_properties(flutter_wrapper_plugin PROPERTIES
+  POSITION_INDEPENDENT_CODE ON)
+set_target_properties(flutter_wrapper_plugin PROPERTIES
+  CXX_VISIBILITY_PRESET hidden)
+target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
+target_include_directories(flutter_wrapper_plugin PUBLIC
+  "${WRAPPER_ROOT}/include"
+)
+add_dependencies(flutter_wrapper_plugin flutter_assemble)
+
+# Wrapper sources needed for the runner.
+add_library(flutter_wrapper_app STATIC
+  ${CPP_WRAPPER_SOURCES_CORE}
+  ${CPP_WRAPPER_SOURCES_APP}
+)
+apply_standard_settings(flutter_wrapper_app)
+target_link_libraries(flutter_wrapper_app PUBLIC flutter)
+target_include_directories(flutter_wrapper_app PUBLIC
+  "${WRAPPER_ROOT}/include"
+)
+add_dependencies(flutter_wrapper_app flutter_assemble)
+
+# === Flutter tool backend ===
+# _phony_ is a non-existent file to force this command to run every time,
+# since currently there's no way to get a full input/output list from the
+# flutter tool.
+set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_")
+set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE)
+add_custom_command(
+  OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
+    ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}
+    ${CPP_WRAPPER_SOURCES_APP}
+    ${PHONY_OUTPUT}
+  COMMAND ${CMAKE_COMMAND} -E env
+    ${FLUTTER_TOOL_ENVIRONMENT}
+    "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
+      windows-x64 $<CONFIG>
+  VERBATIM
+)
+add_custom_target(flutter_assemble DEPENDS
+  "${FLUTTER_LIBRARY}"
+  ${FLUTTER_LIBRARY_HEADERS}
+  ${CPP_WRAPPER_SOURCES_CORE}
+  ${CPP_WRAPPER_SOURCES_PLUGIN}
+  ${CPP_WRAPPER_SOURCES_APP}
+)
diff --git a/frontend/app/windows/flutter/generated_plugin_registrant.cc b/frontend/app/windows/flutter/generated_plugin_registrant.cc
new file mode 100644
index 0000000..8b6d468
--- /dev/null
+++ b/frontend/app/windows/flutter/generated_plugin_registrant.cc
@@ -0,0 +1,11 @@
+//
+//  Generated file. Do not edit.
+//
+
+// clang-format off
+
+#include "generated_plugin_registrant.h"
+
+
+void RegisterPlugins(flutter::PluginRegistry* registry) {
+}
diff --git a/frontend/app/windows/flutter/generated_plugin_registrant.h b/frontend/app/windows/flutter/generated_plugin_registrant.h
new file mode 100644
index 0000000..dc139d8
--- /dev/null
+++ b/frontend/app/windows/flutter/generated_plugin_registrant.h
@@ -0,0 +1,15 @@
+//
+//  Generated file. Do not edit.
+//
+
+// clang-format off
+
+#ifndef GENERATED_PLUGIN_REGISTRANT_
+#define GENERATED_PLUGIN_REGISTRANT_
+
+#include <flutter/plugin_registry.h>
+
+// Registers Flutter plugins.
+void RegisterPlugins(flutter::PluginRegistry* registry);
+
+#endif  // GENERATED_PLUGIN_REGISTRANT_
diff --git a/frontend/app/windows/flutter/generated_plugins.cmake b/frontend/app/windows/flutter/generated_plugins.cmake
new file mode 100644
index 0000000..b93c4c3
--- /dev/null
+++ b/frontend/app/windows/flutter/generated_plugins.cmake
@@ -0,0 +1,23 @@
+#
+# Generated file, do not edit.
+#
+
+list(APPEND FLUTTER_PLUGIN_LIST
+)
+
+list(APPEND FLUTTER_FFI_PLUGIN_LIST
+)
+
+set(PLUGIN_BUNDLED_LIBRARIES)
+
+foreach(plugin ${FLUTTER_PLUGIN_LIST})
+  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})
+  target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
+  list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
+  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
+endforeach(plugin)
+
+foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
+  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
+  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
+endforeach(ffi_plugin)
diff --git a/frontend/app/windows/runner/CMakeLists.txt b/frontend/app/windows/runner/CMakeLists.txt
new file mode 100644
index 0000000..394917c
--- /dev/null
+++ b/frontend/app/windows/runner/CMakeLists.txt
@@ -0,0 +1,40 @@
+cmake_minimum_required(VERSION 3.14)
+project(runner LANGUAGES CXX)
+
+# Define the application target. To change its name, change BINARY_NAME in the
+# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
+# work.
+#
+# Any new source files that you add to the application should be added here.
+add_executable(${BINARY_NAME} WIN32
+  "flutter_window.cpp"
+  "main.cpp"
+  "utils.cpp"
+  "win32_window.cpp"
+  "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
+  "Runner.rc"
+  "runner.exe.manifest"
+)
+
+# Apply the standard set of build settings. This can be removed for applications
+# that need different build settings.
+apply_standard_settings(${BINARY_NAME})
+
+# Add preprocessor definitions for the build version.
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}")
+target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}")
+
+# Disable Windows macros that collide with C++ standard library functions.
+target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
+
+# Add dependency libraries and include directories. Add any application-specific
+# dependencies here.
+target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
+target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib")
+target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
+
+# Run the Flutter tool portions of the build. This must not be removed.
+add_dependencies(${BINARY_NAME} flutter_assemble)
diff --git a/frontend/app/windows/runner/Runner.rc b/frontend/app/windows/runner/Runner.rc
new file mode 100644
index 0000000..9466db6
--- /dev/null
+++ b/frontend/app/windows/runner/Runner.rc
@@ -0,0 +1,121 @@
+// Microsoft Visual C++ generated resource script.
+//
+#pragma code_page(65001)
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+    "#include ""winres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_APP_ICON            ICON                    "resources\\app_icon.ico"
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)
+#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD
+#else
+#define VERSION_AS_NUMBER 1,0,0,0
+#endif
+
+#if defined(FLUTTER_VERSION)
+#define VERSION_AS_STRING FLUTTER_VERSION
+#else
+#define VERSION_AS_STRING "1.0.0"
+#endif
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VERSION_AS_NUMBER
+ PRODUCTVERSION VERSION_AS_NUMBER
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+ FILEFLAGS VS_FF_DEBUG
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_APP
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904e4"
+        BEGIN
+            VALUE "CompanyName", "com.example" "\0"
+            VALUE "FileDescription", "app" "\0"
+            VALUE "FileVersion", VERSION_AS_STRING "\0"
+            VALUE "InternalName", "app" "\0"
+            VALUE "LegalCopyright", "Copyright (C) 2023 com.example. All rights reserved." "\0"
+            VALUE "OriginalFilename", "app.exe" "\0"
+            VALUE "ProductName", "app" "\0"
+            VALUE "ProductVersion", VERSION_AS_STRING "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1252
+    END
+END
+
+#endif    // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
diff --git a/frontend/app/windows/runner/flutter_window.cpp b/frontend/app/windows/runner/flutter_window.cpp
new file mode 100644
index 0000000..955ee30
--- /dev/null
+++ b/frontend/app/windows/runner/flutter_window.cpp
@@ -0,0 +1,71 @@
+#include "flutter_window.h"
+
+#include <optional>
+
+#include "flutter/generated_plugin_registrant.h"
+
+FlutterWindow::FlutterWindow(const flutter::DartProject& project)
+    : project_(project) {}
+
+FlutterWindow::~FlutterWindow() {}
+
+bool FlutterWindow::OnCreate() {
+  if (!Win32Window::OnCreate()) {
+    return false;
+  }
+
+  RECT frame = GetClientArea();
+
+  // The size here must match the window dimensions to avoid unnecessary surface
+  // creation / destruction in the startup path.
+  flutter_controller_ = std::make_unique<flutter::FlutterViewController>(
+      frame.right - frame.left, frame.bottom - frame.top, project_);
+  // Ensure that basic setup of the controller was successful.
+  if (!flutter_controller_->engine() || !flutter_controller_->view()) {
+    return false;
+  }
+  RegisterPlugins(flutter_controller_->engine());
+  SetChildContent(flutter_controller_->view()->GetNativeWindow());
+
+  flutter_controller_->engine()->SetNextFrameCallback([&]() {
+    this->Show();
+  });
+
+  // Flutter can complete the first frame before the "show window" callback is
+  // registered. The following call ensures a frame is pending to ensure the
+  // window is shown. It is a no-op if the first frame hasn't completed yet.
+  flutter_controller_->ForceRedraw();
+
+  return true;
+}
+
+void FlutterWindow::OnDestroy() {
+  if (flutter_controller_) {
+    flutter_controller_ = nullptr;
+  }
+
+  Win32Window::OnDestroy();
+}
+
+LRESULT
+FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
+                              WPARAM const wparam,
+                              LPARAM const lparam) noexcept {
+  // Give Flutter, including plugins, an opportunity to handle window messages.
+  if (flutter_controller_) {
+    std::optional<LRESULT> result =
+        flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
+                                                      lparam);
+    if (result) {
+      return *result;
+    }
+  }
+
+  switch (message) {
+    case WM_FONTCHANGE:
+      flutter_controller_->engine()->ReloadSystemFonts();
+      break;
+  }
+
+  return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
+}
diff --git a/frontend/app/windows/runner/flutter_window.h b/frontend/app/windows/runner/flutter_window.h
new file mode 100644
index 0000000..6da0652
--- /dev/null
+++ b/frontend/app/windows/runner/flutter_window.h
@@ -0,0 +1,33 @@
+#ifndef RUNNER_FLUTTER_WINDOW_H_
+#define RUNNER_FLUTTER_WINDOW_H_
+
+#include <flutter/dart_project.h>
+#include <flutter/flutter_view_controller.h>
+
+#include <memory>
+
+#include "win32_window.h"
+
+// A window that does nothing but host a Flutter view.
+class FlutterWindow : public Win32Window {
+ public:
+  // Creates a new FlutterWindow hosting a Flutter view running |project|.
+  explicit FlutterWindow(const flutter::DartProject& project);
+  virtual ~FlutterWindow();
+
+ protected:
+  // Win32Window:
+  bool OnCreate() override;
+  void OnDestroy() override;
+  LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
+                         LPARAM const lparam) noexcept override;
+
+ private:
+  // The project to run.
+  flutter::DartProject project_;
+
+  // The Flutter instance hosted by this window.
+  std::unique_ptr<flutter::FlutterViewController> flutter_controller_;
+};
+
+#endif  // RUNNER_FLUTTER_WINDOW_H_
diff --git a/frontend/app/windows/runner/main.cpp b/frontend/app/windows/runner/main.cpp
new file mode 100644
index 0000000..bc9bfa3
--- /dev/null
+++ b/frontend/app/windows/runner/main.cpp
@@ -0,0 +1,43 @@
+#include <flutter/dart_project.h>
+#include <flutter/flutter_view_controller.h>
+#include <windows.h>
+
+#include "flutter_window.h"
+#include "utils.h"
+
+int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
+                      _In_ wchar_t *command_line, _In_ int show_command) {
+  // Attach to console when present (e.g., 'flutter run') or create a
+  // new console when running with a debugger.
+  if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
+    CreateAndAttachConsole();
+  }
+
+  // Initialize COM, so that it is available for use in the library and/or
+  // plugins.
+  ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
+
+  flutter::DartProject project(L"data");
+
+  std::vector<std::string> command_line_arguments =
+      GetCommandLineArguments();
+
+  project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
+
+  FlutterWindow window(project);
+  Win32Window::Point origin(10, 10);
+  Win32Window::Size size(1280, 720);
+  if (!window.Create(L"app", origin, size)) {
+    return EXIT_FAILURE;
+  }
+  window.SetQuitOnClose(true);
+
+  ::MSG msg;
+  while (::GetMessage(&msg, nullptr, 0, 0)) {
+    ::TranslateMessage(&msg);
+    ::DispatchMessage(&msg);
+  }
+
+  ::CoUninitialize();
+  return EXIT_SUCCESS;
+}
diff --git a/frontend/app/windows/runner/resource.h b/frontend/app/windows/runner/resource.h
new file mode 100644
index 0000000..66a65d1
--- /dev/null
+++ b/frontend/app/windows/runner/resource.h
@@ -0,0 +1,16 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by Runner.rc
+//
+#define IDI_APP_ICON                    101
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        102
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1001
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
diff --git a/frontend/app/windows/runner/resources/app_icon.ico b/frontend/app/windows/runner/resources/app_icon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..c04e20caf6370ebb9253ad831cc31de4a9c965f6
GIT binary patch
literal 33772
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

literal 0
HcmV?d00001

diff --git a/frontend/app/windows/runner/runner.exe.manifest b/frontend/app/windows/runner/runner.exe.manifest
new file mode 100644
index 0000000..a42ea76
--- /dev/null
+++ b/frontend/app/windows/runner/runner.exe.manifest
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <application xmlns="urn:schemas-microsoft-com:asm.v3">
+    <windowsSettings>
+      <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
+    </windowsSettings>
+  </application>
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+    <application>
+      <!-- Windows 10 and Windows 11 -->
+      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+      <!-- Windows 8.1 -->
+      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+      <!-- Windows 8 -->
+      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+      <!-- Windows 7 -->
+      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+    </application>
+  </compatibility>
+</assembly>
diff --git a/frontend/app/windows/runner/utils.cpp b/frontend/app/windows/runner/utils.cpp
new file mode 100644
index 0000000..b2b0873
--- /dev/null
+++ b/frontend/app/windows/runner/utils.cpp
@@ -0,0 +1,65 @@
+#include "utils.h"
+
+#include <flutter_windows.h>
+#include <io.h>
+#include <stdio.h>
+#include <windows.h>
+
+#include <iostream>
+
+void CreateAndAttachConsole() {
+  if (::AllocConsole()) {
+    FILE *unused;
+    if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
+      _dup2(_fileno(stdout), 1);
+    }
+    if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
+      _dup2(_fileno(stdout), 2);
+    }
+    std::ios::sync_with_stdio();
+    FlutterDesktopResyncOutputStreams();
+  }
+}
+
+std::vector<std::string> GetCommandLineArguments() {
+  // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.
+  int argc;
+  wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
+  if (argv == nullptr) {
+    return std::vector<std::string>();
+  }
+
+  std::vector<std::string> command_line_arguments;
+
+  // Skip the first argument as it's the binary name.
+  for (int i = 1; i < argc; i++) {
+    command_line_arguments.push_back(Utf8FromUtf16(argv[i]));
+  }
+
+  ::LocalFree(argv);
+
+  return command_line_arguments;
+}
+
+std::string Utf8FromUtf16(const wchar_t* utf16_string) {
+  if (utf16_string == nullptr) {
+    return std::string();
+  }
+  int target_length = ::WideCharToMultiByte(
+      CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
+      -1, nullptr, 0, nullptr, nullptr)
+    -1; // remove the trailing null character
+  int input_length = (int)wcslen(utf16_string);
+  std::string utf8_string;
+  if (target_length <= 0 || target_length > utf8_string.max_size()) {
+    return utf8_string;
+  }
+  utf8_string.resize(target_length);
+  int converted_length = ::WideCharToMultiByte(
+      CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
+      input_length, utf8_string.data(), target_length, nullptr, nullptr);
+  if (converted_length == 0) {
+    return std::string();
+  }
+  return utf8_string;
+}
diff --git a/frontend/app/windows/runner/utils.h b/frontend/app/windows/runner/utils.h
new file mode 100644
index 0000000..3879d54
--- /dev/null
+++ b/frontend/app/windows/runner/utils.h
@@ -0,0 +1,19 @@
+#ifndef RUNNER_UTILS_H_
+#define RUNNER_UTILS_H_
+
+#include <string>
+#include <vector>
+
+// Creates a console for the process, and redirects stdout and stderr to
+// it for both the runner and the Flutter library.
+void CreateAndAttachConsole();
+
+// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string
+// encoded in UTF-8. Returns an empty std::string on failure.
+std::string Utf8FromUtf16(const wchar_t* utf16_string);
+
+// Gets the command line arguments passed in as a std::vector<std::string>,
+// encoded in UTF-8. Returns an empty std::vector<std::string> on failure.
+std::vector<std::string> GetCommandLineArguments();
+
+#endif  // RUNNER_UTILS_H_
diff --git a/frontend/app/windows/runner/win32_window.cpp b/frontend/app/windows/runner/win32_window.cpp
new file mode 100644
index 0000000..60608d0
--- /dev/null
+++ b/frontend/app/windows/runner/win32_window.cpp
@@ -0,0 +1,288 @@
+#include "win32_window.h"
+
+#include <dwmapi.h>
+#include <flutter_windows.h>
+
+#include "resource.h"
+
+namespace {
+
+/// Window attribute that enables dark mode window decorations.
+///
+/// Redefined in case the developer's machine has a Windows SDK older than
+/// version 10.0.22000.0.
+/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
+#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
+#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
+#endif
+
+constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW";
+
+/// Registry key for app theme preference.
+///
+/// A value of 0 indicates apps should use dark mode. A non-zero or missing
+/// value indicates apps should use light mode.
+constexpr const wchar_t kGetPreferredBrightnessRegKey[] =
+  L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
+constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme";
+
+// The number of Win32Window objects that currently exist.
+static int g_active_window_count = 0;
+
+using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd);
+
+// Scale helper to convert logical scaler values to physical using passed in
+// scale factor
+int Scale(int source, double scale_factor) {
+  return static_cast<int>(source * scale_factor);
+}
+
+// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.
+// This API is only needed for PerMonitor V1 awareness mode.
+void EnableFullDpiSupportIfAvailable(HWND hwnd) {
+  HMODULE user32_module = LoadLibraryA("User32.dll");
+  if (!user32_module) {
+    return;
+  }
+  auto enable_non_client_dpi_scaling =
+      reinterpret_cast<EnableNonClientDpiScaling*>(
+          GetProcAddress(user32_module, "EnableNonClientDpiScaling"));
+  if (enable_non_client_dpi_scaling != nullptr) {
+    enable_non_client_dpi_scaling(hwnd);
+  }
+  FreeLibrary(user32_module);
+}
+
+}  // namespace
+
+// Manages the Win32Window's window class registration.
+class WindowClassRegistrar {
+ public:
+  ~WindowClassRegistrar() = default;
+
+  // Returns the singleton registrar instance.
+  static WindowClassRegistrar* GetInstance() {
+    if (!instance_) {
+      instance_ = new WindowClassRegistrar();
+    }
+    return instance_;
+  }
+
+  // Returns the name of the window class, registering the class if it hasn't
+  // previously been registered.
+  const wchar_t* GetWindowClass();
+
+  // Unregisters the window class. Should only be called if there are no
+  // instances of the window.
+  void UnregisterWindowClass();
+
+ private:
+  WindowClassRegistrar() = default;
+
+  static WindowClassRegistrar* instance_;
+
+  bool class_registered_ = false;
+};
+
+WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr;
+
+const wchar_t* WindowClassRegistrar::GetWindowClass() {
+  if (!class_registered_) {
+    WNDCLASS window_class{};
+    window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
+    window_class.lpszClassName = kWindowClassName;
+    window_class.style = CS_HREDRAW | CS_VREDRAW;
+    window_class.cbClsExtra = 0;
+    window_class.cbWndExtra = 0;
+    window_class.hInstance = GetModuleHandle(nullptr);
+    window_class.hIcon =
+        LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON));
+    window_class.hbrBackground = 0;
+    window_class.lpszMenuName = nullptr;
+    window_class.lpfnWndProc = Win32Window::WndProc;
+    RegisterClass(&window_class);
+    class_registered_ = true;
+  }
+  return kWindowClassName;
+}
+
+void WindowClassRegistrar::UnregisterWindowClass() {
+  UnregisterClass(kWindowClassName, nullptr);
+  class_registered_ = false;
+}
+
+Win32Window::Win32Window() {
+  ++g_active_window_count;
+}
+
+Win32Window::~Win32Window() {
+  --g_active_window_count;
+  Destroy();
+}
+
+bool Win32Window::Create(const std::wstring& title,
+                         const Point& origin,
+                         const Size& size) {
+  Destroy();
+
+  const wchar_t* window_class =
+      WindowClassRegistrar::GetInstance()->GetWindowClass();
+
+  const POINT target_point = {static_cast<LONG>(origin.x),
+                              static_cast<LONG>(origin.y)};
+  HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST);
+  UINT dpi = FlutterDesktopGetDpiForMonitor(monitor);
+  double scale_factor = dpi / 96.0;
+
+  HWND window = CreateWindow(
+      window_class, title.c_str(), WS_OVERLAPPEDWINDOW,
+      Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),
+      Scale(size.width, scale_factor), Scale(size.height, scale_factor),
+      nullptr, nullptr, GetModuleHandle(nullptr), this);
+
+  if (!window) {
+    return false;
+  }
+
+  UpdateTheme(window);
+
+  return OnCreate();
+}
+
+bool Win32Window::Show() {
+  return ShowWindow(window_handle_, SW_SHOWNORMAL);
+}
+
+// static
+LRESULT CALLBACK Win32Window::WndProc(HWND const window,
+                                      UINT const message,
+                                      WPARAM const wparam,
+                                      LPARAM const lparam) noexcept {
+  if (message == WM_NCCREATE) {
+    auto window_struct = reinterpret_cast<CREATESTRUCT*>(lparam);
+    SetWindowLongPtr(window, GWLP_USERDATA,
+                     reinterpret_cast<LONG_PTR>(window_struct->lpCreateParams));
+
+    auto that = static_cast<Win32Window*>(window_struct->lpCreateParams);
+    EnableFullDpiSupportIfAvailable(window);
+    that->window_handle_ = window;
+  } else if (Win32Window* that = GetThisFromHandle(window)) {
+    return that->MessageHandler(window, message, wparam, lparam);
+  }
+
+  return DefWindowProc(window, message, wparam, lparam);
+}
+
+LRESULT
+Win32Window::MessageHandler(HWND hwnd,
+                            UINT const message,
+                            WPARAM const wparam,
+                            LPARAM const lparam) noexcept {
+  switch (message) {
+    case WM_DESTROY:
+      window_handle_ = nullptr;
+      Destroy();
+      if (quit_on_close_) {
+        PostQuitMessage(0);
+      }
+      return 0;
+
+    case WM_DPICHANGED: {
+      auto newRectSize = reinterpret_cast<RECT*>(lparam);
+      LONG newWidth = newRectSize->right - newRectSize->left;
+      LONG newHeight = newRectSize->bottom - newRectSize->top;
+
+      SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth,
+                   newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
+
+      return 0;
+    }
+    case WM_SIZE: {
+      RECT rect = GetClientArea();
+      if (child_content_ != nullptr) {
+        // Size and position the child window.
+        MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left,
+                   rect.bottom - rect.top, TRUE);
+      }
+      return 0;
+    }
+
+    case WM_ACTIVATE:
+      if (child_content_ != nullptr) {
+        SetFocus(child_content_);
+      }
+      return 0;
+
+    case WM_DWMCOLORIZATIONCOLORCHANGED:
+      UpdateTheme(hwnd);
+      return 0;
+  }
+
+  return DefWindowProc(window_handle_, message, wparam, lparam);
+}
+
+void Win32Window::Destroy() {
+  OnDestroy();
+
+  if (window_handle_) {
+    DestroyWindow(window_handle_);
+    window_handle_ = nullptr;
+  }
+  if (g_active_window_count == 0) {
+    WindowClassRegistrar::GetInstance()->UnregisterWindowClass();
+  }
+}
+
+Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {
+  return reinterpret_cast<Win32Window*>(
+      GetWindowLongPtr(window, GWLP_USERDATA));
+}
+
+void Win32Window::SetChildContent(HWND content) {
+  child_content_ = content;
+  SetParent(content, window_handle_);
+  RECT frame = GetClientArea();
+
+  MoveWindow(content, frame.left, frame.top, frame.right - frame.left,
+             frame.bottom - frame.top, true);
+
+  SetFocus(child_content_);
+}
+
+RECT Win32Window::GetClientArea() {
+  RECT frame;
+  GetClientRect(window_handle_, &frame);
+  return frame;
+}
+
+HWND Win32Window::GetHandle() {
+  return window_handle_;
+}
+
+void Win32Window::SetQuitOnClose(bool quit_on_close) {
+  quit_on_close_ = quit_on_close;
+}
+
+bool Win32Window::OnCreate() {
+  // No-op; provided for subclasses.
+  return true;
+}
+
+void Win32Window::OnDestroy() {
+  // No-op; provided for subclasses.
+}
+
+void Win32Window::UpdateTheme(HWND const window) {
+  DWORD light_mode;
+  DWORD light_mode_size = sizeof(light_mode);
+  LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,
+                               kGetPreferredBrightnessRegValue,
+                               RRF_RT_REG_DWORD, nullptr, &light_mode,
+                               &light_mode_size);
+
+  if (result == ERROR_SUCCESS) {
+    BOOL enable_dark_mode = light_mode == 0;
+    DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE,
+                          &enable_dark_mode, sizeof(enable_dark_mode));
+  }
+}
diff --git a/frontend/app/windows/runner/win32_window.h b/frontend/app/windows/runner/win32_window.h
new file mode 100644
index 0000000..e901dde
--- /dev/null
+++ b/frontend/app/windows/runner/win32_window.h
@@ -0,0 +1,102 @@
+#ifndef RUNNER_WIN32_WINDOW_H_
+#define RUNNER_WIN32_WINDOW_H_
+
+#include <windows.h>
+
+#include <functional>
+#include <memory>
+#include <string>
+
+// A class abstraction for a high DPI-aware Win32 Window. Intended to be
+// inherited from by classes that wish to specialize with custom
+// rendering and input handling
+class Win32Window {
+ public:
+  struct Point {
+    unsigned int x;
+    unsigned int y;
+    Point(unsigned int x, unsigned int y) : x(x), y(y) {}
+  };
+
+  struct Size {
+    unsigned int width;
+    unsigned int height;
+    Size(unsigned int width, unsigned int height)
+        : width(width), height(height) {}
+  };
+
+  Win32Window();
+  virtual ~Win32Window();
+
+  // Creates a win32 window with |title| that is positioned and sized using
+  // |origin| and |size|. New windows are created on the default monitor. Window
+  // sizes are specified to the OS in physical pixels, hence to ensure a
+  // consistent size this function will scale the inputted width and height as
+  // as appropriate for the default monitor. The window is invisible until
+  // |Show| is called. Returns true if the window was created successfully.
+  bool Create(const std::wstring& title, const Point& origin, const Size& size);
+
+  // Show the current window. Returns true if the window was successfully shown.
+  bool Show();
+
+  // Release OS resources associated with window.
+  void Destroy();
+
+  // Inserts |content| into the window tree.
+  void SetChildContent(HWND content);
+
+  // Returns the backing Window handle to enable clients to set icon and other
+  // window properties. Returns nullptr if the window has been destroyed.
+  HWND GetHandle();
+
+  // If true, closing this window will quit the application.
+  void SetQuitOnClose(bool quit_on_close);
+
+  // Return a RECT representing the bounds of the current client area.
+  RECT GetClientArea();
+
+ protected:
+  // Processes and route salient window messages for mouse handling,
+  // size change and DPI. Delegates handling of these to member overloads that
+  // inheriting classes can handle.
+  virtual LRESULT MessageHandler(HWND window,
+                                 UINT const message,
+                                 WPARAM const wparam,
+                                 LPARAM const lparam) noexcept;
+
+  // Called when CreateAndShow is called, allowing subclass window-related
+  // setup. Subclasses should return false if setup fails.
+  virtual bool OnCreate();
+
+  // Called when Destroy is called.
+  virtual void OnDestroy();
+
+ private:
+  friend class WindowClassRegistrar;
+
+  // OS callback called by message pump. Handles the WM_NCCREATE message which
+  // is passed when the non-client area is being created and enables automatic
+  // non-client DPI scaling so that the non-client area automatically
+  // responds to changes in DPI. All other messages are handled by
+  // MessageHandler.
+  static LRESULT CALLBACK WndProc(HWND const window,
+                                  UINT const message,
+                                  WPARAM const wparam,
+                                  LPARAM const lparam) noexcept;
+
+  // Retrieves a class instance pointer for |window|
+  static Win32Window* GetThisFromHandle(HWND const window) noexcept;
+
+  // Update the window frame's theme to match the system theme.
+  static void UpdateTheme(HWND const window);
+
+  bool quit_on_close_ = false;
+
+  // window handle for top level window.
+  HWND window_handle_ = nullptr;
+
+  // window handle for hosted content.
+  HWND child_content_ = nullptr;
+};
+
+#endif  // RUNNER_WIN32_WINDOW_H_

From 5f3952ea229355a9bc941fdc9cf904ef50af7338 Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Tue, 24 Oct 2023 13:23:09 +0200
Subject: [PATCH 02/24] ft/adds first functional grpc-call: create_account

---
 Makefile                                      |   2 +-
 frontend/app/lib/gapi/client.dart             |  66 +-
 frontend/app/lib/main.dart                    |   2 +-
 frontend/app/lib/pages/main_screen.dart       |  22 +-
 frontend/app/lib/pb/account.pb.dart           |  22 +-
 frontend/app/lib/pb/account.pbserver.dart     |  14 -
 frontend/app/lib/pb/account_info.pb.dart      |  42 +-
 .../app/lib/pb/account_info.pbserver.dart     |  14 -
 frontend/app/lib/pb/document.pb.dart          |  32 +-
 frontend/app/lib/pb/document.pbserver.dart    |  14 -
 frontend/app/lib/pb/payment.pb.dart           |  22 +-
 frontend/app/lib/pb/payment.pbserver.dart     |  14 -
 frontend/app/lib/pb/person.pb.dart            |  32 +-
 frontend/app/lib/pb/person.pbserver.dart      |  14 -
 frontend/app/lib/pb/returns_log.pb.dart       |  22 +-
 frontend/app/lib/pb/returns_log.pbserver.dart |  14 -
 .../lib/pb/rpc_block_session.pbserver.dart    |  14 -
 .../app/lib/pb/rpc_create_account.pb.dart     |  12 +-
 .../lib/pb/rpc_create_account.pbserver.dart   |  14 -
 .../lib/pb/rpc_create_account_info.pb.dart    |  24 +-
 .../pb/rpc_create_account_info.pbserver.dart  |  14 -
 .../app/lib/pb/rpc_create_payment.pb.dart     |  12 +-
 .../lib/pb/rpc_create_payment.pbserver.dart   |  14 -
 frontend/app/lib/pb/rpc_create_person.pb.dart |  24 +-
 .../lib/pb/rpc_create_person.pbserver.dart    |  14 -
 .../lib/pb/rpc_delete_document.pbserver.dart  |  14 -
 .../lib/pb/rpc_delete_payment.pbserver.dart   |  14 -
 .../lib/pb/rpc_delete_person.pbserver.dart    |  14 -
 frontend/app/lib/pb/rpc_get_account.pb.dart   |  12 +-
 .../app/lib/pb/rpc_get_account.pbserver.dart  |  14 -
 .../app/lib/pb/rpc_get_account_info.pb.dart   |  12 +-
 .../lib/pb/rpc_get_account_info.pbserver.dart |  14 -
 frontend/app/lib/pb/rpc_get_payment.pb.dart   |  12 +-
 .../app/lib/pb/rpc_get_payment.pbserver.dart  |  14 -
 frontend/app/lib/pb/rpc_get_person.pb.dart    |  12 +-
 .../app/lib/pb/rpc_get_person.pbserver.dart   |  14 -
 .../app/lib/pb/rpc_list_account_info.pb.dart  |   8 +-
 .../pb/rpc_list_account_info.pbserver.dart    |  14 -
 frontend/app/lib/pb/rpc_list_accounts.pb.dart |   8 +-
 .../lib/pb/rpc_list_accounts.pbserver.dart    |  14 -
 frontend/app/lib/pb/rpc_list_payments.pb.dart |   8 +-
 .../lib/pb/rpc_list_payments.pbserver.dart    |  14 -
 frontend/app/lib/pb/rpc_list_persons.pb.dart  |   8 +-
 .../app/lib/pb/rpc_list_persons.pbserver.dart |  14 -
 .../rpc_list_returns_log_by_person_id.pb.dart |   8 +-
 ...ist_returns_log_by_person_id.pbserver.dart |  14 -
 frontend/app/lib/pb/rpc_list_sessions.pb.dart |   8 +-
 .../lib/pb/rpc_list_sessions.pbserver.dart    |  14 -
 frontend/app/lib/pb/rpc_login.pb.dart         |  22 +-
 frontend/app/lib/pb/rpc_login.pbserver.dart   |  14 -
 frontend/app/lib/pb/rpc_refresh_token.pb.dart |  12 +-
 .../lib/pb/rpc_refresh_token.pbserver.dart    |  14 -
 .../app/lib/pb/rpc_update_account.pb.dart     |  12 +-
 .../lib/pb/rpc_update_account.pbserver.dart   |  14 -
 .../lib/pb/rpc_update_account_info.pb.dart    |  24 +-
 .../pb/rpc_update_account_info.pbserver.dart  |  14 -
 .../lib/pb/rpc_update_account_privacy.pb.dart |  12 +-
 .../rpc_update_account_privacy.pbserver.dart  |  14 -
 .../app/lib/pb/rpc_update_payment.pb.dart     |  12 +-
 .../lib/pb/rpc_update_payment.pbserver.dart   |  14 -
 frontend/app/lib/pb/rpc_update_person.pb.dart |  24 +-
 .../lib/pb/rpc_update_person.pbserver.dart    |  14 -
 .../app/lib/pb/rpc_upload_document.pb.dart    |  12 +-
 .../lib/pb/rpc_upload_document.pbserver.dart  |  14 -
 .../app/lib/pb/rpc_verify_email.pbserver.dart |  14 -
 frontend/app/lib/pb/service_df.pb.dart        | 118 ----
 frontend/app/lib/pb/service_df.pbgrpc.dart    | 605 ++++++++++++++++++
 frontend/app/lib/pb/service_df.pbjson.dart    | 217 -------
 frontend/app/lib/pb/service_df.pbserver.dart  | 147 -----
 frontend/app/lib/pb/session.pb.dart           |  22 +-
 frontend/app/lib/pb/session.pbserver.dart     |  14 -
 71 files changed, 899 insertions(+), 1248 deletions(-)
 delete mode 100644 frontend/app/lib/pb/account.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/account_info.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/document.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/payment.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/person.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/returns_log.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_block_session.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_create_account.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_create_account_info.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_create_payment.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_create_person.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_delete_document.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_delete_payment.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_delete_person.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_get_account.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_get_account_info.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_get_payment.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_get_person.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_list_account_info.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_list_accounts.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_list_payments.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_list_persons.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_list_sessions.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_login.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_refresh_token.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_update_account.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_update_account_info.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_update_account_privacy.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_update_payment.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_update_person.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_upload_document.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/rpc_verify_email.pbserver.dart
 create mode 100644 frontend/app/lib/pb/service_df.pbgrpc.dart
 delete mode 100644 frontend/app/lib/pb/service_df.pbserver.dart
 delete mode 100644 frontend/app/lib/pb/session.pbserver.dart

diff --git a/Makefile b/Makefile
index 48c328f..718f525 100644
--- a/Makefile
+++ b/Makefile
@@ -99,7 +99,7 @@ proto:
 proto_app:
 	cd frontend/app && \
 	rm -f lib/pb/*.dart && \
-	protoc -I=../../bff/proto --dart_out=lib/pb ../../bff/proto/*.proto
+	protoc --dart_out=grpc:lib/pb -I=../../bff/proto/ ../../bff/proto/*.proto && \
 	cd ../..
 
 evans:
diff --git a/frontend/app/lib/gapi/client.dart b/frontend/app/lib/gapi/client.dart
index 8ffe047..91abab8 100644
--- a/frontend/app/lib/gapi/client.dart
+++ b/frontend/app/lib/gapi/client.dart
@@ -1,45 +1,33 @@
-import 'package:app/pb/rpc_login.pbserver.dart';
-
-import 'package:app/pb/service_df.pbserver.dart';
-
+import 'package:app/pb/rpc_create_account.pb.dart';
+import 'package:app/pb/service_df.pbgrpc.dart';
+import 'package:flutter/foundation.dart';
 import 'package:grpc/grpc.dart';
 
-import 'package:protobuf/protobuf.dart' as $pb;
-
-import 'package:app/pb/service_df.pb.dart';
-
 class Client {
-  late dfApi stub;
+  String baseUrl = 'localhost';
+  int port = 9090;
 
-//  Future<void> main(List<String> args) async {
-//     final channel = ClientChannel('127.0.0.1',
-//         port: 8080,
-//         options:
-//             const ChannelOptions(credentials: ChannelCredentials.insecure()));
-//     stub = dfServiceBase(channel,
-//         options: CallOptions(timeout: Duration(seconds: 30)));
-//     // Run all of the demos in order.
-//     try {
-//       await runGetFeature();
-//       await runListFeatures();
-//       await runRecordRoute();
-//       await runRouteChat();
-//     } catch (e) {
-//       print('Caught error: $e');
-//     }
-//     await channel.shutdown();
-//   }
-  // Future<LoginResponse> login(
-  //     $pb.ServerContext ctx, LoginRequest request) async {}
-  // final channel = ClientChannel(
-  //   '127.0.0.1',
-  //   port: 9090,
-  //   options: const ChannelOptions(
-  //     credentials: ChannelCredentials.insecure(),
-  //   ),
-  // );
+  dfClient stub = dfClient(
+    ClientChannel('10.0.2.2',
+        port: 9090,
+        options: const ChannelOptions(
+          credentials: ChannelCredentials.insecure(),
+        )),
+    options: CallOptions(
+      timeout: const Duration(seconds: 5),
+    ),
+  );
+  Future<void> main(List<String> args) async {}
 
-  // dfApi stub = dfApi(
-  //   channel,
-  // );
+  Future<CreateAccountResponse> createAccount(
+      CreateAccountRequest request) async {
+    // CreateAccountResponse response;
+    try {
+      final response = stub.createAccount(request);
+      return response;
+    } catch (e) {
+      print('caught error: $e');
+    }
+    return CreateAccountResponse();
+  }
 }
diff --git a/frontend/app/lib/main.dart b/frontend/app/lib/main.dart
index 697c294..bc298a4 100644
--- a/frontend/app/lib/main.dart
+++ b/frontend/app/lib/main.dart
@@ -3,5 +3,5 @@ import 'package:flutter/material.dart';
 import 'package:app/pages/main_screen.dart';
 
 void main() {
-  runApp(const MainScreen());
+  runApp(MaterialApp(home: MainScreen()));
 }
diff --git a/frontend/app/lib/pages/main_screen.dart b/frontend/app/lib/pages/main_screen.dart
index 932bc0c..6719e77 100644
--- a/frontend/app/lib/pages/main_screen.dart
+++ b/frontend/app/lib/pages/main_screen.dart
@@ -1,15 +1,31 @@
+import 'package:app/gapi/client.dart';
+import 'package:app/pb/rpc_create_account.pb.dart';
 import 'package:flutter/material.dart';
 
 class MainScreen extends StatelessWidget {
-  const MainScreen({super.key});
+  MainScreen({super.key});
+
+  Client client = Client();
+
+  void test() {
+    client.stub.createAccount(
+      CreateAccountRequest(email: "dev@itsscb.de", password: "secret-key123"),
+    );
+  }
 
   @override
   Widget build(BuildContext context) {
-    return const Scaffold(
+    return Scaffold(
       body: Column(
         mainAxisAlignment: MainAxisAlignment.center,
         crossAxisAlignment: CrossAxisAlignment.center,
-        children: [],
+        children: [
+          TextButton(
+              onPressed: () {
+                test();
+              },
+              child: const Text('Button'))
+        ],
       ),
     );
   }
diff --git a/frontend/app/lib/pb/account.pb.dart b/frontend/app/lib/pb/account.pb.dart
index dbf09e2..6d897c5 100644
--- a/frontend/app/lib/pb/account.pb.dart
+++ b/frontend/app/lib/pb/account.pb.dart
@@ -14,16 +14,16 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'google/protobuf/timestamp.pb.dart' as $0;
+import 'google/protobuf/timestamp.pb.dart' as $27;
 
 class Account extends $pb.GeneratedMessage {
   factory Account({
     $fixnum.Int64? id,
     $core.String? email,
     $core.String? secretKey,
-    $0.Timestamp? emailVerifiedTime,
+    $27.Timestamp? emailVerifiedTime,
     $core.bool? emailVerified,
-    $0.Timestamp? privacyAcceptedDate,
+    $27.Timestamp? privacyAcceptedDate,
     $core.int? permissionLevel,
   }) {
     final $result = create();
@@ -58,9 +58,9 @@ class Account extends $pb.GeneratedMessage {
     ..a<$fixnum.Int64>(1, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
     ..aOS(2, _omitFieldNames ? '' : 'email')
     ..aOS(3, _omitFieldNames ? '' : 'secretKey')
-    ..aOM<$0.Timestamp>(9, _omitFieldNames ? '' : 'emailVerifiedTime', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(9, _omitFieldNames ? '' : 'emailVerifiedTime', subBuilder: $27.Timestamp.create)
     ..aOB(10, _omitFieldNames ? '' : 'emailVerified')
-    ..aOM<$0.Timestamp>(12, _omitFieldNames ? '' : 'privacyAcceptedDate', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(12, _omitFieldNames ? '' : 'privacyAcceptedDate', subBuilder: $27.Timestamp.create)
     ..a<$core.int>(13, _omitFieldNames ? '' : 'permissionLevel', $pb.PbFieldType.O3)
     ..hasRequiredFields = false
   ;
@@ -114,15 +114,15 @@ class Account extends $pb.GeneratedMessage {
   void clearSecretKey() => clearField(3);
 
   @$pb.TagNumber(9)
-  $0.Timestamp get emailVerifiedTime => $_getN(3);
+  $27.Timestamp get emailVerifiedTime => $_getN(3);
   @$pb.TagNumber(9)
-  set emailVerifiedTime($0.Timestamp v) { setField(9, v); }
+  set emailVerifiedTime($27.Timestamp v) { setField(9, v); }
   @$pb.TagNumber(9)
   $core.bool hasEmailVerifiedTime() => $_has(3);
   @$pb.TagNumber(9)
   void clearEmailVerifiedTime() => clearField(9);
   @$pb.TagNumber(9)
-  $0.Timestamp ensureEmailVerifiedTime() => $_ensure(3);
+  $27.Timestamp ensureEmailVerifiedTime() => $_ensure(3);
 
   @$pb.TagNumber(10)
   $core.bool get emailVerified => $_getBF(4);
@@ -134,15 +134,15 @@ class Account extends $pb.GeneratedMessage {
   void clearEmailVerified() => clearField(10);
 
   @$pb.TagNumber(12)
-  $0.Timestamp get privacyAcceptedDate => $_getN(5);
+  $27.Timestamp get privacyAcceptedDate => $_getN(5);
   @$pb.TagNumber(12)
-  set privacyAcceptedDate($0.Timestamp v) { setField(12, v); }
+  set privacyAcceptedDate($27.Timestamp v) { setField(12, v); }
   @$pb.TagNumber(12)
   $core.bool hasPrivacyAcceptedDate() => $_has(5);
   @$pb.TagNumber(12)
   void clearPrivacyAcceptedDate() => clearField(12);
   @$pb.TagNumber(12)
-  $0.Timestamp ensurePrivacyAcceptedDate() => $_ensure(5);
+  $27.Timestamp ensurePrivacyAcceptedDate() => $_ensure(5);
 
   @$pb.TagNumber(13)
   $core.int get permissionLevel => $_getIZ(6);
diff --git a/frontend/app/lib/pb/account.pbserver.dart b/frontend/app/lib/pb/account.pbserver.dart
deleted file mode 100644
index 50774a9..0000000
--- a/frontend/app/lib/pb/account.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: account.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'account.pb.dart';
-
diff --git a/frontend/app/lib/pb/account_info.pb.dart b/frontend/app/lib/pb/account_info.pb.dart
index 38089b9..9db0a1e 100644
--- a/frontend/app/lib/pb/account_info.pb.dart
+++ b/frontend/app/lib/pb/account_info.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'google/protobuf/timestamp.pb.dart' as $0;
+import 'google/protobuf/timestamp.pb.dart' as $27;
 
 class AccountInfo extends $pb.GeneratedMessage {
   factory AccountInfo({
@@ -25,15 +25,15 @@ class AccountInfo extends $pb.GeneratedMessage {
     $core.String? city,
     $core.String? zip,
     $core.String? country,
-    $0.Timestamp? birthday,
+    $27.Timestamp? birthday,
     $core.String? phone,
     $core.bool? privacyAccepted,
-    $0.Timestamp? privacyAcceptedDate,
+    $27.Timestamp? privacyAcceptedDate,
     $core.int? permissionLevel,
     $core.String? creator,
-    $0.Timestamp? created,
+    $27.Timestamp? created,
     $core.String? changer,
-    $0.Timestamp? changed,
+    $27.Timestamp? changed,
   }) {
     final $result = create();
     if (accountId != null) {
@@ -98,15 +98,15 @@ class AccountInfo extends $pb.GeneratedMessage {
     ..aOS(6, _omitFieldNames ? '' : 'city')
     ..aOS(7, _omitFieldNames ? '' : 'zip')
     ..aOS(8, _omitFieldNames ? '' : 'country')
-    ..aOM<$0.Timestamp>(9, _omitFieldNames ? '' : 'birthday', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(9, _omitFieldNames ? '' : 'birthday', subBuilder: $27.Timestamp.create)
     ..aOS(10, _omitFieldNames ? '' : 'phone')
     ..aOB(11, _omitFieldNames ? '' : 'privacyAccepted')
-    ..aOM<$0.Timestamp>(12, _omitFieldNames ? '' : 'privacyAcceptedDate', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(12, _omitFieldNames ? '' : 'privacyAcceptedDate', subBuilder: $27.Timestamp.create)
     ..a<$core.int>(13, _omitFieldNames ? '' : 'permissionLevel', $pb.PbFieldType.O3)
     ..aOS(14, _omitFieldNames ? '' : 'creator')
-    ..aOM<$0.Timestamp>(15, _omitFieldNames ? '' : 'created', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(15, _omitFieldNames ? '' : 'created', subBuilder: $27.Timestamp.create)
     ..aOS(16, _omitFieldNames ? '' : 'changer')
-    ..aOM<$0.Timestamp>(17, _omitFieldNames ? '' : 'changed', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(17, _omitFieldNames ? '' : 'changed', subBuilder: $27.Timestamp.create)
     ..hasRequiredFields = false
   ;
 
@@ -195,15 +195,15 @@ class AccountInfo extends $pb.GeneratedMessage {
   void clearCountry() => clearField(8);
 
   @$pb.TagNumber(9)
-  $0.Timestamp get birthday => $_getN(7);
+  $27.Timestamp get birthday => $_getN(7);
   @$pb.TagNumber(9)
-  set birthday($0.Timestamp v) { setField(9, v); }
+  set birthday($27.Timestamp v) { setField(9, v); }
   @$pb.TagNumber(9)
   $core.bool hasBirthday() => $_has(7);
   @$pb.TagNumber(9)
   void clearBirthday() => clearField(9);
   @$pb.TagNumber(9)
-  $0.Timestamp ensureBirthday() => $_ensure(7);
+  $27.Timestamp ensureBirthday() => $_ensure(7);
 
   @$pb.TagNumber(10)
   $core.String get phone => $_getSZ(8);
@@ -224,15 +224,15 @@ class AccountInfo extends $pb.GeneratedMessage {
   void clearPrivacyAccepted() => clearField(11);
 
   @$pb.TagNumber(12)
-  $0.Timestamp get privacyAcceptedDate => $_getN(10);
+  $27.Timestamp get privacyAcceptedDate => $_getN(10);
   @$pb.TagNumber(12)
-  set privacyAcceptedDate($0.Timestamp v) { setField(12, v); }
+  set privacyAcceptedDate($27.Timestamp v) { setField(12, v); }
   @$pb.TagNumber(12)
   $core.bool hasPrivacyAcceptedDate() => $_has(10);
   @$pb.TagNumber(12)
   void clearPrivacyAcceptedDate() => clearField(12);
   @$pb.TagNumber(12)
-  $0.Timestamp ensurePrivacyAcceptedDate() => $_ensure(10);
+  $27.Timestamp ensurePrivacyAcceptedDate() => $_ensure(10);
 
   @$pb.TagNumber(13)
   $core.int get permissionLevel => $_getIZ(11);
@@ -253,15 +253,15 @@ class AccountInfo extends $pb.GeneratedMessage {
   void clearCreator() => clearField(14);
 
   @$pb.TagNumber(15)
-  $0.Timestamp get created => $_getN(13);
+  $27.Timestamp get created => $_getN(13);
   @$pb.TagNumber(15)
-  set created($0.Timestamp v) { setField(15, v); }
+  set created($27.Timestamp v) { setField(15, v); }
   @$pb.TagNumber(15)
   $core.bool hasCreated() => $_has(13);
   @$pb.TagNumber(15)
   void clearCreated() => clearField(15);
   @$pb.TagNumber(15)
-  $0.Timestamp ensureCreated() => $_ensure(13);
+  $27.Timestamp ensureCreated() => $_ensure(13);
 
   @$pb.TagNumber(16)
   $core.String get changer => $_getSZ(14);
@@ -273,15 +273,15 @@ class AccountInfo extends $pb.GeneratedMessage {
   void clearChanger() => clearField(16);
 
   @$pb.TagNumber(17)
-  $0.Timestamp get changed => $_getN(15);
+  $27.Timestamp get changed => $_getN(15);
   @$pb.TagNumber(17)
-  set changed($0.Timestamp v) { setField(17, v); }
+  set changed($27.Timestamp v) { setField(17, v); }
   @$pb.TagNumber(17)
   $core.bool hasChanged() => $_has(15);
   @$pb.TagNumber(17)
   void clearChanged() => clearField(17);
   @$pb.TagNumber(17)
-  $0.Timestamp ensureChanged() => $_ensure(15);
+  $27.Timestamp ensureChanged() => $_ensure(15);
 }
 
 
diff --git a/frontend/app/lib/pb/account_info.pbserver.dart b/frontend/app/lib/pb/account_info.pbserver.dart
deleted file mode 100644
index 0f19252..0000000
--- a/frontend/app/lib/pb/account_info.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: account_info.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'account_info.pb.dart';
-
diff --git a/frontend/app/lib/pb/document.pb.dart b/frontend/app/lib/pb/document.pb.dart
index 3aa549b..515c25c 100644
--- a/frontend/app/lib/pb/document.pb.dart
+++ b/frontend/app/lib/pb/document.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'google/protobuf/timestamp.pb.dart' as $0;
+import 'google/protobuf/timestamp.pb.dart' as $27;
 
 class Document extends $pb.GeneratedMessage {
   factory Document({
@@ -26,11 +26,11 @@ class Document extends $pb.GeneratedMessage {
     $core.String? url,
     $core.bool? valid,
     $core.String? validatedBy,
-    $0.Timestamp? validDate,
+    $27.Timestamp? validDate,
     $core.String? creator,
-    $0.Timestamp? created,
+    $27.Timestamp? created,
     $core.String? changer,
-    $0.Timestamp? changed,
+    $27.Timestamp? changed,
     $fixnum.Int64? id,
   }) {
     final $result = create();
@@ -91,11 +91,11 @@ class Document extends $pb.GeneratedMessage {
     ..aOS(6, _omitFieldNames ? '' : 'url')
     ..aOB(7, _omitFieldNames ? '' : 'valid')
     ..aOS(8, _omitFieldNames ? '' : 'validatedBy')
-    ..aOM<$0.Timestamp>(9, _omitFieldNames ? '' : 'validDate', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(9, _omitFieldNames ? '' : 'validDate', subBuilder: $27.Timestamp.create)
     ..aOS(10, _omitFieldNames ? '' : 'creator')
-    ..aOM<$0.Timestamp>(11, _omitFieldNames ? '' : 'created', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(11, _omitFieldNames ? '' : 'created', subBuilder: $27.Timestamp.create)
     ..aOS(12, _omitFieldNames ? '' : 'changer')
-    ..aOM<$0.Timestamp>(13, _omitFieldNames ? '' : 'changed', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(13, _omitFieldNames ? '' : 'changed', subBuilder: $27.Timestamp.create)
     ..a<$fixnum.Int64>(14, _omitFieldNames ? '' : 'id', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
     ..hasRequiredFields = false
   ;
@@ -194,15 +194,15 @@ class Document extends $pb.GeneratedMessage {
   void clearValidatedBy() => clearField(8);
 
   @$pb.TagNumber(9)
-  $0.Timestamp get validDate => $_getN(8);
+  $27.Timestamp get validDate => $_getN(8);
   @$pb.TagNumber(9)
-  set validDate($0.Timestamp v) { setField(9, v); }
+  set validDate($27.Timestamp v) { setField(9, v); }
   @$pb.TagNumber(9)
   $core.bool hasValidDate() => $_has(8);
   @$pb.TagNumber(9)
   void clearValidDate() => clearField(9);
   @$pb.TagNumber(9)
-  $0.Timestamp ensureValidDate() => $_ensure(8);
+  $27.Timestamp ensureValidDate() => $_ensure(8);
 
   @$pb.TagNumber(10)
   $core.String get creator => $_getSZ(9);
@@ -214,15 +214,15 @@ class Document extends $pb.GeneratedMessage {
   void clearCreator() => clearField(10);
 
   @$pb.TagNumber(11)
-  $0.Timestamp get created => $_getN(10);
+  $27.Timestamp get created => $_getN(10);
   @$pb.TagNumber(11)
-  set created($0.Timestamp v) { setField(11, v); }
+  set created($27.Timestamp v) { setField(11, v); }
   @$pb.TagNumber(11)
   $core.bool hasCreated() => $_has(10);
   @$pb.TagNumber(11)
   void clearCreated() => clearField(11);
   @$pb.TagNumber(11)
-  $0.Timestamp ensureCreated() => $_ensure(10);
+  $27.Timestamp ensureCreated() => $_ensure(10);
 
   @$pb.TagNumber(12)
   $core.String get changer => $_getSZ(11);
@@ -234,15 +234,15 @@ class Document extends $pb.GeneratedMessage {
   void clearChanger() => clearField(12);
 
   @$pb.TagNumber(13)
-  $0.Timestamp get changed => $_getN(12);
+  $27.Timestamp get changed => $_getN(12);
   @$pb.TagNumber(13)
-  set changed($0.Timestamp v) { setField(13, v); }
+  set changed($27.Timestamp v) { setField(13, v); }
   @$pb.TagNumber(13)
   $core.bool hasChanged() => $_has(12);
   @$pb.TagNumber(13)
   void clearChanged() => clearField(13);
   @$pb.TagNumber(13)
-  $0.Timestamp ensureChanged() => $_ensure(12);
+  $27.Timestamp ensureChanged() => $_ensure(12);
 
   @$pb.TagNumber(14)
   $fixnum.Int64 get id => $_getI64(13);
diff --git a/frontend/app/lib/pb/document.pbserver.dart b/frontend/app/lib/pb/document.pbserver.dart
deleted file mode 100644
index 532039c..0000000
--- a/frontend/app/lib/pb/document.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: document.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'document.pb.dart';
-
diff --git a/frontend/app/lib/pb/payment.pb.dart b/frontend/app/lib/pb/payment.pb.dart
index 29a550b..328f131 100644
--- a/frontend/app/lib/pb/payment.pb.dart
+++ b/frontend/app/lib/pb/payment.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'google/protobuf/timestamp.pb.dart' as $0;
+import 'google/protobuf/timestamp.pb.dart' as $27;
 
 class Payment extends $pb.GeneratedMessage {
   factory Payment({
@@ -29,9 +29,9 @@ class Payment extends $pb.GeneratedMessage {
     $core.String? paymentSystem,
     $core.String? type,
     $core.String? creator,
-    $0.Timestamp? created,
+    $27.Timestamp? created,
     $core.String? changer,
-    $0.Timestamp? changed,
+    $27.Timestamp? changed,
   }) {
     final $result = create();
     if (id != null) {
@@ -94,9 +94,9 @@ class Payment extends $pb.GeneratedMessage {
     ..aOS(9, _omitFieldNames ? '' : 'paymentSystem')
     ..aOS(10, _omitFieldNames ? '' : 'type')
     ..aOS(11, _omitFieldNames ? '' : 'creator')
-    ..aOM<$0.Timestamp>(12, _omitFieldNames ? '' : 'created', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(12, _omitFieldNames ? '' : 'created', subBuilder: $27.Timestamp.create)
     ..aOS(13, _omitFieldNames ? '' : 'changer')
-    ..aOM<$0.Timestamp>(14, _omitFieldNames ? '' : 'changed', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(14, _omitFieldNames ? '' : 'changed', subBuilder: $27.Timestamp.create)
     ..hasRequiredFields = false
   ;
 
@@ -221,15 +221,15 @@ class Payment extends $pb.GeneratedMessage {
   void clearCreator() => clearField(11);
 
   @$pb.TagNumber(12)
-  $0.Timestamp get created => $_getN(11);
+  $27.Timestamp get created => $_getN(11);
   @$pb.TagNumber(12)
-  set created($0.Timestamp v) { setField(12, v); }
+  set created($27.Timestamp v) { setField(12, v); }
   @$pb.TagNumber(12)
   $core.bool hasCreated() => $_has(11);
   @$pb.TagNumber(12)
   void clearCreated() => clearField(12);
   @$pb.TagNumber(12)
-  $0.Timestamp ensureCreated() => $_ensure(11);
+  $27.Timestamp ensureCreated() => $_ensure(11);
 
   @$pb.TagNumber(13)
   $core.String get changer => $_getSZ(12);
@@ -241,15 +241,15 @@ class Payment extends $pb.GeneratedMessage {
   void clearChanger() => clearField(13);
 
   @$pb.TagNumber(14)
-  $0.Timestamp get changed => $_getN(13);
+  $27.Timestamp get changed => $_getN(13);
   @$pb.TagNumber(14)
-  set changed($0.Timestamp v) { setField(14, v); }
+  set changed($27.Timestamp v) { setField(14, v); }
   @$pb.TagNumber(14)
   $core.bool hasChanged() => $_has(13);
   @$pb.TagNumber(14)
   void clearChanged() => clearField(14);
   @$pb.TagNumber(14)
-  $0.Timestamp ensureChanged() => $_ensure(13);
+  $27.Timestamp ensureChanged() => $_ensure(13);
 }
 
 
diff --git a/frontend/app/lib/pb/payment.pbserver.dart b/frontend/app/lib/pb/payment.pbserver.dart
deleted file mode 100644
index da6b450..0000000
--- a/frontend/app/lib/pb/payment.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: payment.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'payment.pb.dart';
-
diff --git a/frontend/app/lib/pb/person.pb.dart b/frontend/app/lib/pb/person.pb.dart
index 62a8d88..265a285 100644
--- a/frontend/app/lib/pb/person.pb.dart
+++ b/frontend/app/lib/pb/person.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'google/protobuf/timestamp.pb.dart' as $0;
+import 'google/protobuf/timestamp.pb.dart' as $27;
 
 class Person extends $pb.GeneratedMessage {
   factory Person({
@@ -26,11 +26,11 @@ class Person extends $pb.GeneratedMessage {
     $core.String? city,
     $core.String? zip,
     $core.String? country,
-    $0.Timestamp? birthday,
+    $27.Timestamp? birthday,
     $core.String? creator,
-    $0.Timestamp? created,
+    $27.Timestamp? created,
     $core.String? changer,
-    $0.Timestamp? changed,
+    $27.Timestamp? changed,
   }) {
     final $result = create();
     if (id != null) {
@@ -87,11 +87,11 @@ class Person extends $pb.GeneratedMessage {
     ..aOS(6, _omitFieldNames ? '' : 'city')
     ..aOS(7, _omitFieldNames ? '' : 'zip')
     ..aOS(8, _omitFieldNames ? '' : 'country')
-    ..aOM<$0.Timestamp>(9, _omitFieldNames ? '' : 'birthday', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(9, _omitFieldNames ? '' : 'birthday', subBuilder: $27.Timestamp.create)
     ..aOS(10, _omitFieldNames ? '' : 'creator')
-    ..aOM<$0.Timestamp>(11, _omitFieldNames ? '' : 'created', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(11, _omitFieldNames ? '' : 'created', subBuilder: $27.Timestamp.create)
     ..aOS(12, _omitFieldNames ? '' : 'changer')
-    ..aOM<$0.Timestamp>(13, _omitFieldNames ? '' : 'changed', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(13, _omitFieldNames ? '' : 'changed', subBuilder: $27.Timestamp.create)
     ..hasRequiredFields = false
   ;
 
@@ -189,15 +189,15 @@ class Person extends $pb.GeneratedMessage {
   void clearCountry() => clearField(8);
 
   @$pb.TagNumber(9)
-  $0.Timestamp get birthday => $_getN(8);
+  $27.Timestamp get birthday => $_getN(8);
   @$pb.TagNumber(9)
-  set birthday($0.Timestamp v) { setField(9, v); }
+  set birthday($27.Timestamp v) { setField(9, v); }
   @$pb.TagNumber(9)
   $core.bool hasBirthday() => $_has(8);
   @$pb.TagNumber(9)
   void clearBirthday() => clearField(9);
   @$pb.TagNumber(9)
-  $0.Timestamp ensureBirthday() => $_ensure(8);
+  $27.Timestamp ensureBirthday() => $_ensure(8);
 
   @$pb.TagNumber(10)
   $core.String get creator => $_getSZ(9);
@@ -209,15 +209,15 @@ class Person extends $pb.GeneratedMessage {
   void clearCreator() => clearField(10);
 
   @$pb.TagNumber(11)
-  $0.Timestamp get created => $_getN(10);
+  $27.Timestamp get created => $_getN(10);
   @$pb.TagNumber(11)
-  set created($0.Timestamp v) { setField(11, v); }
+  set created($27.Timestamp v) { setField(11, v); }
   @$pb.TagNumber(11)
   $core.bool hasCreated() => $_has(10);
   @$pb.TagNumber(11)
   void clearCreated() => clearField(11);
   @$pb.TagNumber(11)
-  $0.Timestamp ensureCreated() => $_ensure(10);
+  $27.Timestamp ensureCreated() => $_ensure(10);
 
   @$pb.TagNumber(12)
   $core.String get changer => $_getSZ(11);
@@ -229,15 +229,15 @@ class Person extends $pb.GeneratedMessage {
   void clearChanger() => clearField(12);
 
   @$pb.TagNumber(13)
-  $0.Timestamp get changed => $_getN(12);
+  $27.Timestamp get changed => $_getN(12);
   @$pb.TagNumber(13)
-  set changed($0.Timestamp v) { setField(13, v); }
+  set changed($27.Timestamp v) { setField(13, v); }
   @$pb.TagNumber(13)
   $core.bool hasChanged() => $_has(12);
   @$pb.TagNumber(13)
   void clearChanged() => clearField(13);
   @$pb.TagNumber(13)
-  $0.Timestamp ensureChanged() => $_ensure(12);
+  $27.Timestamp ensureChanged() => $_ensure(12);
 }
 
 
diff --git a/frontend/app/lib/pb/person.pbserver.dart b/frontend/app/lib/pb/person.pbserver.dart
deleted file mode 100644
index 659fc7a..0000000
--- a/frontend/app/lib/pb/person.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: person.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'person.pb.dart';
-
diff --git a/frontend/app/lib/pb/returns_log.pb.dart b/frontend/app/lib/pb/returns_log.pb.dart
index d365d08..1ade51c 100644
--- a/frontend/app/lib/pb/returns_log.pb.dart
+++ b/frontend/app/lib/pb/returns_log.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'google/protobuf/timestamp.pb.dart' as $0;
+import 'google/protobuf/timestamp.pb.dart' as $27;
 
 class ReturnsLog extends $pb.GeneratedMessage {
   factory ReturnsLog({
@@ -23,9 +23,9 @@ class ReturnsLog extends $pb.GeneratedMessage {
     $fixnum.Int64? mailId,
     $core.String? status,
     $core.String? creator,
-    $0.Timestamp? created,
+    $27.Timestamp? created,
     $core.String? changer,
-    $0.Timestamp? changed,
+    $27.Timestamp? changed,
   }) {
     final $result = create();
     if (id != null) {
@@ -64,9 +64,9 @@ class ReturnsLog extends $pb.GeneratedMessage {
     ..a<$fixnum.Int64>(3, _omitFieldNames ? '' : 'mailId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
     ..aOS(4, _omitFieldNames ? '' : 'status')
     ..aOS(5, _omitFieldNames ? '' : 'creator')
-    ..aOM<$0.Timestamp>(6, _omitFieldNames ? '' : 'created', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(6, _omitFieldNames ? '' : 'created', subBuilder: $27.Timestamp.create)
     ..aOS(7, _omitFieldNames ? '' : 'changer')
-    ..aOM<$0.Timestamp>(8, _omitFieldNames ? '' : 'changed', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(8, _omitFieldNames ? '' : 'changed', subBuilder: $27.Timestamp.create)
     ..hasRequiredFields = false
   ;
 
@@ -137,15 +137,15 @@ class ReturnsLog extends $pb.GeneratedMessage {
   void clearCreator() => clearField(5);
 
   @$pb.TagNumber(6)
-  $0.Timestamp get created => $_getN(5);
+  $27.Timestamp get created => $_getN(5);
   @$pb.TagNumber(6)
-  set created($0.Timestamp v) { setField(6, v); }
+  set created($27.Timestamp v) { setField(6, v); }
   @$pb.TagNumber(6)
   $core.bool hasCreated() => $_has(5);
   @$pb.TagNumber(6)
   void clearCreated() => clearField(6);
   @$pb.TagNumber(6)
-  $0.Timestamp ensureCreated() => $_ensure(5);
+  $27.Timestamp ensureCreated() => $_ensure(5);
 
   @$pb.TagNumber(7)
   $core.String get changer => $_getSZ(6);
@@ -157,15 +157,15 @@ class ReturnsLog extends $pb.GeneratedMessage {
   void clearChanger() => clearField(7);
 
   @$pb.TagNumber(8)
-  $0.Timestamp get changed => $_getN(7);
+  $27.Timestamp get changed => $_getN(7);
   @$pb.TagNumber(8)
-  set changed($0.Timestamp v) { setField(8, v); }
+  set changed($27.Timestamp v) { setField(8, v); }
   @$pb.TagNumber(8)
   $core.bool hasChanged() => $_has(7);
   @$pb.TagNumber(8)
   void clearChanged() => clearField(8);
   @$pb.TagNumber(8)
-  $0.Timestamp ensureChanged() => $_ensure(7);
+  $27.Timestamp ensureChanged() => $_ensure(7);
 }
 
 
diff --git a/frontend/app/lib/pb/returns_log.pbserver.dart b/frontend/app/lib/pb/returns_log.pbserver.dart
deleted file mode 100644
index ca8149a..0000000
--- a/frontend/app/lib/pb/returns_log.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: returns_log.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'returns_log.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_block_session.pbserver.dart b/frontend/app/lib/pb/rpc_block_session.pbserver.dart
deleted file mode 100644
index 57b2eee..0000000
--- a/frontend/app/lib/pb/rpc_block_session.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_block_session.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_block_session.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_create_account.pb.dart b/frontend/app/lib/pb/rpc_create_account.pb.dart
index 15e65df..d5c1508 100644
--- a/frontend/app/lib/pb/rpc_create_account.pb.dart
+++ b/frontend/app/lib/pb/rpc_create_account.pb.dart
@@ -13,7 +13,7 @@ import 'dart:core' as $core;
 
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'account.pb.dart' as $2;
+import 'account.pb.dart' as $29;
 
 class CreateAccountRequest extends $pb.GeneratedMessage {
   factory CreateAccountRequest({
@@ -81,7 +81,7 @@ class CreateAccountRequest extends $pb.GeneratedMessage {
 
 class CreateAccountResponse extends $pb.GeneratedMessage {
   factory CreateAccountResponse({
-    $2.Account? account,
+    $29.Account? account,
   }) {
     final $result = create();
     if (account != null) {
@@ -94,7 +94,7 @@ class CreateAccountResponse extends $pb.GeneratedMessage {
   factory CreateAccountResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CreateAccountResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..aOM<$2.Account>(1, _omitFieldNames ? '' : 'account', subBuilder: $2.Account.create)
+    ..aOM<$29.Account>(1, _omitFieldNames ? '' : 'account', subBuilder: $29.Account.create)
     ..hasRequiredFields = false
   ;
 
@@ -120,15 +120,15 @@ class CreateAccountResponse extends $pb.GeneratedMessage {
   static CreateAccountResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $2.Account get account => $_getN(0);
+  $29.Account get account => $_getN(0);
   @$pb.TagNumber(1)
-  set account($2.Account v) { setField(1, v); }
+  set account($29.Account v) { setField(1, v); }
   @$pb.TagNumber(1)
   $core.bool hasAccount() => $_has(0);
   @$pb.TagNumber(1)
   void clearAccount() => clearField(1);
   @$pb.TagNumber(1)
-  $2.Account ensureAccount() => $_ensure(0);
+  $29.Account ensureAccount() => $_ensure(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_create_account.pbserver.dart b/frontend/app/lib/pb/rpc_create_account.pbserver.dart
deleted file mode 100644
index 533f0eb..0000000
--- a/frontend/app/lib/pb/rpc_create_account.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_create_account.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_create_account.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_create_account_info.pb.dart b/frontend/app/lib/pb/rpc_create_account_info.pb.dart
index 2ae91f1..e8b6311 100644
--- a/frontend/app/lib/pb/rpc_create_account_info.pb.dart
+++ b/frontend/app/lib/pb/rpc_create_account_info.pb.dart
@@ -14,8 +14,8 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'account_info.pb.dart' as $1;
-import 'google/protobuf/timestamp.pb.dart' as $0;
+import 'account_info.pb.dart' as $28;
+import 'google/protobuf/timestamp.pb.dart' as $27;
 
 class CreateAccountInfoRequest extends $pb.GeneratedMessage {
   factory CreateAccountInfoRequest({
@@ -27,7 +27,7 @@ class CreateAccountInfoRequest extends $pb.GeneratedMessage {
     $core.String? zip,
     $core.String? country,
     $core.String? phone,
-    $0.Timestamp? birthday,
+    $27.Timestamp? birthday,
     $core.bool? privacyAccepted,
   }) {
     final $result = create();
@@ -76,7 +76,7 @@ class CreateAccountInfoRequest extends $pb.GeneratedMessage {
     ..aOS(7, _omitFieldNames ? '' : 'zip')
     ..aOS(8, _omitFieldNames ? '' : 'country')
     ..aOS(9, _omitFieldNames ? '' : 'phone')
-    ..aOM<$0.Timestamp>(10, _omitFieldNames ? '' : 'birthday', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(10, _omitFieldNames ? '' : 'birthday', subBuilder: $27.Timestamp.create)
     ..aOB(11, _omitFieldNames ? '' : 'privacyAccepted')
     ..hasRequiredFields = false
   ;
@@ -175,15 +175,15 @@ class CreateAccountInfoRequest extends $pb.GeneratedMessage {
   void clearPhone() => clearField(9);
 
   @$pb.TagNumber(10)
-  $0.Timestamp get birthday => $_getN(8);
+  $27.Timestamp get birthday => $_getN(8);
   @$pb.TagNumber(10)
-  set birthday($0.Timestamp v) { setField(10, v); }
+  set birthday($27.Timestamp v) { setField(10, v); }
   @$pb.TagNumber(10)
   $core.bool hasBirthday() => $_has(8);
   @$pb.TagNumber(10)
   void clearBirthday() => clearField(10);
   @$pb.TagNumber(10)
-  $0.Timestamp ensureBirthday() => $_ensure(8);
+  $27.Timestamp ensureBirthday() => $_ensure(8);
 
   @$pb.TagNumber(11)
   $core.bool get privacyAccepted => $_getBF(9);
@@ -197,7 +197,7 @@ class CreateAccountInfoRequest extends $pb.GeneratedMessage {
 
 class CreateAccountInfoResponse extends $pb.GeneratedMessage {
   factory CreateAccountInfoResponse({
-    $1.AccountInfo? accountInfo,
+    $28.AccountInfo? accountInfo,
   }) {
     final $result = create();
     if (accountInfo != null) {
@@ -210,7 +210,7 @@ class CreateAccountInfoResponse extends $pb.GeneratedMessage {
   factory CreateAccountInfoResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CreateAccountInfoResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..aOM<$1.AccountInfo>(1, _omitFieldNames ? '' : 'accountInfo', subBuilder: $1.AccountInfo.create)
+    ..aOM<$28.AccountInfo>(1, _omitFieldNames ? '' : 'accountInfo', subBuilder: $28.AccountInfo.create)
     ..hasRequiredFields = false
   ;
 
@@ -236,15 +236,15 @@ class CreateAccountInfoResponse extends $pb.GeneratedMessage {
   static CreateAccountInfoResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $1.AccountInfo get accountInfo => $_getN(0);
+  $28.AccountInfo get accountInfo => $_getN(0);
   @$pb.TagNumber(1)
-  set accountInfo($1.AccountInfo v) { setField(1, v); }
+  set accountInfo($28.AccountInfo v) { setField(1, v); }
   @$pb.TagNumber(1)
   $core.bool hasAccountInfo() => $_has(0);
   @$pb.TagNumber(1)
   void clearAccountInfo() => clearField(1);
   @$pb.TagNumber(1)
-  $1.AccountInfo ensureAccountInfo() => $_ensure(0);
+  $28.AccountInfo ensureAccountInfo() => $_ensure(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_create_account_info.pbserver.dart b/frontend/app/lib/pb/rpc_create_account_info.pbserver.dart
deleted file mode 100644
index 36d73df..0000000
--- a/frontend/app/lib/pb/rpc_create_account_info.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_create_account_info.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_create_account_info.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_create_payment.pb.dart b/frontend/app/lib/pb/rpc_create_payment.pb.dart
index bed6474..082d8ef 100644
--- a/frontend/app/lib/pb/rpc_create_payment.pb.dart
+++ b/frontend/app/lib/pb/rpc_create_payment.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'payment.pb.dart' as $3;
+import 'payment.pb.dart' as $30;
 
 class CreatePaymentRequest extends $pb.GeneratedMessage {
   factory CreatePaymentRequest({
@@ -180,7 +180,7 @@ class CreatePaymentRequest extends $pb.GeneratedMessage {
 
 class CreatePaymentResponse extends $pb.GeneratedMessage {
   factory CreatePaymentResponse({
-    $3.Payment? payment,
+    $30.Payment? payment,
   }) {
     final $result = create();
     if (payment != null) {
@@ -193,7 +193,7 @@ class CreatePaymentResponse extends $pb.GeneratedMessage {
   factory CreatePaymentResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CreatePaymentResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..aOM<$3.Payment>(1, _omitFieldNames ? '' : 'payment', subBuilder: $3.Payment.create)
+    ..aOM<$30.Payment>(1, _omitFieldNames ? '' : 'payment', subBuilder: $30.Payment.create)
     ..hasRequiredFields = false
   ;
 
@@ -219,15 +219,15 @@ class CreatePaymentResponse extends $pb.GeneratedMessage {
   static CreatePaymentResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $3.Payment get payment => $_getN(0);
+  $30.Payment get payment => $_getN(0);
   @$pb.TagNumber(1)
-  set payment($3.Payment v) { setField(1, v); }
+  set payment($30.Payment v) { setField(1, v); }
   @$pb.TagNumber(1)
   $core.bool hasPayment() => $_has(0);
   @$pb.TagNumber(1)
   void clearPayment() => clearField(1);
   @$pb.TagNumber(1)
-  $3.Payment ensurePayment() => $_ensure(0);
+  $30.Payment ensurePayment() => $_ensure(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_create_payment.pbserver.dart b/frontend/app/lib/pb/rpc_create_payment.pbserver.dart
deleted file mode 100644
index c732f6e..0000000
--- a/frontend/app/lib/pb/rpc_create_payment.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_create_payment.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_create_payment.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_create_person.pb.dart b/frontend/app/lib/pb/rpc_create_person.pb.dart
index 35dcb1a..3e165d4 100644
--- a/frontend/app/lib/pb/rpc_create_person.pb.dart
+++ b/frontend/app/lib/pb/rpc_create_person.pb.dart
@@ -14,8 +14,8 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'google/protobuf/timestamp.pb.dart' as $0;
-import 'person.pb.dart' as $4;
+import 'google/protobuf/timestamp.pb.dart' as $27;
+import 'person.pb.dart' as $31;
 
 class CreatePersonRequest extends $pb.GeneratedMessage {
   factory CreatePersonRequest({
@@ -26,7 +26,7 @@ class CreatePersonRequest extends $pb.GeneratedMessage {
     $core.String? city,
     $core.String? zip,
     $core.String? country,
-    $0.Timestamp? birthday,
+    $27.Timestamp? birthday,
   }) {
     final $result = create();
     if (accountId != null) {
@@ -67,7 +67,7 @@ class CreatePersonRequest extends $pb.GeneratedMessage {
     ..aOS(5, _omitFieldNames ? '' : 'city')
     ..aOS(6, _omitFieldNames ? '' : 'zip')
     ..aOS(7, _omitFieldNames ? '' : 'country')
-    ..aOM<$0.Timestamp>(8, _omitFieldNames ? '' : 'birthday', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(8, _omitFieldNames ? '' : 'birthday', subBuilder: $27.Timestamp.create)
     ..hasRequiredFields = false
   ;
 
@@ -156,20 +156,20 @@ class CreatePersonRequest extends $pb.GeneratedMessage {
   void clearCountry() => clearField(7);
 
   @$pb.TagNumber(8)
-  $0.Timestamp get birthday => $_getN(7);
+  $27.Timestamp get birthday => $_getN(7);
   @$pb.TagNumber(8)
-  set birthday($0.Timestamp v) { setField(8, v); }
+  set birthday($27.Timestamp v) { setField(8, v); }
   @$pb.TagNumber(8)
   $core.bool hasBirthday() => $_has(7);
   @$pb.TagNumber(8)
   void clearBirthday() => clearField(8);
   @$pb.TagNumber(8)
-  $0.Timestamp ensureBirthday() => $_ensure(7);
+  $27.Timestamp ensureBirthday() => $_ensure(7);
 }
 
 class CreatePersonResponse extends $pb.GeneratedMessage {
   factory CreatePersonResponse({
-    $4.Person? person,
+    $31.Person? person,
   }) {
     final $result = create();
     if (person != null) {
@@ -182,7 +182,7 @@ class CreatePersonResponse extends $pb.GeneratedMessage {
   factory CreatePersonResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'CreatePersonResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..aOM<$4.Person>(1, _omitFieldNames ? '' : 'person', subBuilder: $4.Person.create)
+    ..aOM<$31.Person>(1, _omitFieldNames ? '' : 'person', subBuilder: $31.Person.create)
     ..hasRequiredFields = false
   ;
 
@@ -208,15 +208,15 @@ class CreatePersonResponse extends $pb.GeneratedMessage {
   static CreatePersonResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $4.Person get person => $_getN(0);
+  $31.Person get person => $_getN(0);
   @$pb.TagNumber(1)
-  set person($4.Person v) { setField(1, v); }
+  set person($31.Person v) { setField(1, v); }
   @$pb.TagNumber(1)
   $core.bool hasPerson() => $_has(0);
   @$pb.TagNumber(1)
   void clearPerson() => clearField(1);
   @$pb.TagNumber(1)
-  $4.Person ensurePerson() => $_ensure(0);
+  $31.Person ensurePerson() => $_ensure(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_create_person.pbserver.dart b/frontend/app/lib/pb/rpc_create_person.pbserver.dart
deleted file mode 100644
index 2b5f8fd..0000000
--- a/frontend/app/lib/pb/rpc_create_person.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_create_person.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_create_person.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_delete_document.pbserver.dart b/frontend/app/lib/pb/rpc_delete_document.pbserver.dart
deleted file mode 100644
index 57d37b6..0000000
--- a/frontend/app/lib/pb/rpc_delete_document.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_delete_document.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_delete_document.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_delete_payment.pbserver.dart b/frontend/app/lib/pb/rpc_delete_payment.pbserver.dart
deleted file mode 100644
index 4e22b6f..0000000
--- a/frontend/app/lib/pb/rpc_delete_payment.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_delete_payment.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_delete_payment.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_delete_person.pbserver.dart b/frontend/app/lib/pb/rpc_delete_person.pbserver.dart
deleted file mode 100644
index 1fd5c66..0000000
--- a/frontend/app/lib/pb/rpc_delete_person.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_delete_person.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_delete_person.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_get_account.pb.dart b/frontend/app/lib/pb/rpc_get_account.pb.dart
index 8d129d1..ab7db4c 100644
--- a/frontend/app/lib/pb/rpc_get_account.pb.dart
+++ b/frontend/app/lib/pb/rpc_get_account.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'account.pb.dart' as $2;
+import 'account.pb.dart' as $29;
 
 class GetAccountRequest extends $pb.GeneratedMessage {
   factory GetAccountRequest({
@@ -68,7 +68,7 @@ class GetAccountRequest extends $pb.GeneratedMessage {
 
 class GetAccountResponse extends $pb.GeneratedMessage {
   factory GetAccountResponse({
-    $2.Account? account,
+    $29.Account? account,
   }) {
     final $result = create();
     if (account != null) {
@@ -81,7 +81,7 @@ class GetAccountResponse extends $pb.GeneratedMessage {
   factory GetAccountResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetAccountResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..aOM<$2.Account>(1, _omitFieldNames ? '' : 'account', subBuilder: $2.Account.create)
+    ..aOM<$29.Account>(1, _omitFieldNames ? '' : 'account', subBuilder: $29.Account.create)
     ..hasRequiredFields = false
   ;
 
@@ -107,15 +107,15 @@ class GetAccountResponse extends $pb.GeneratedMessage {
   static GetAccountResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $2.Account get account => $_getN(0);
+  $29.Account get account => $_getN(0);
   @$pb.TagNumber(1)
-  set account($2.Account v) { setField(1, v); }
+  set account($29.Account v) { setField(1, v); }
   @$pb.TagNumber(1)
   $core.bool hasAccount() => $_has(0);
   @$pb.TagNumber(1)
   void clearAccount() => clearField(1);
   @$pb.TagNumber(1)
-  $2.Account ensureAccount() => $_ensure(0);
+  $29.Account ensureAccount() => $_ensure(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_get_account.pbserver.dart b/frontend/app/lib/pb/rpc_get_account.pbserver.dart
deleted file mode 100644
index d2c87f6..0000000
--- a/frontend/app/lib/pb/rpc_get_account.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_get_account.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_get_account.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_get_account_info.pb.dart b/frontend/app/lib/pb/rpc_get_account_info.pb.dart
index d11787f..92c48f9 100644
--- a/frontend/app/lib/pb/rpc_get_account_info.pb.dart
+++ b/frontend/app/lib/pb/rpc_get_account_info.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'account_info.pb.dart' as $1;
+import 'account_info.pb.dart' as $28;
 
 class GetAccountInfoRequest extends $pb.GeneratedMessage {
   factory GetAccountInfoRequest({
@@ -68,7 +68,7 @@ class GetAccountInfoRequest extends $pb.GeneratedMessage {
 
 class GetAccountInfoResponse extends $pb.GeneratedMessage {
   factory GetAccountInfoResponse({
-    $1.AccountInfo? accountInfo,
+    $28.AccountInfo? accountInfo,
   }) {
     final $result = create();
     if (accountInfo != null) {
@@ -81,7 +81,7 @@ class GetAccountInfoResponse extends $pb.GeneratedMessage {
   factory GetAccountInfoResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetAccountInfoResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..aOM<$1.AccountInfo>(1, _omitFieldNames ? '' : 'accountInfo', subBuilder: $1.AccountInfo.create)
+    ..aOM<$28.AccountInfo>(1, _omitFieldNames ? '' : 'accountInfo', subBuilder: $28.AccountInfo.create)
     ..hasRequiredFields = false
   ;
 
@@ -107,15 +107,15 @@ class GetAccountInfoResponse extends $pb.GeneratedMessage {
   static GetAccountInfoResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $1.AccountInfo get accountInfo => $_getN(0);
+  $28.AccountInfo get accountInfo => $_getN(0);
   @$pb.TagNumber(1)
-  set accountInfo($1.AccountInfo v) { setField(1, v); }
+  set accountInfo($28.AccountInfo v) { setField(1, v); }
   @$pb.TagNumber(1)
   $core.bool hasAccountInfo() => $_has(0);
   @$pb.TagNumber(1)
   void clearAccountInfo() => clearField(1);
   @$pb.TagNumber(1)
-  $1.AccountInfo ensureAccountInfo() => $_ensure(0);
+  $28.AccountInfo ensureAccountInfo() => $_ensure(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_get_account_info.pbserver.dart b/frontend/app/lib/pb/rpc_get_account_info.pbserver.dart
deleted file mode 100644
index 82075ad..0000000
--- a/frontend/app/lib/pb/rpc_get_account_info.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_get_account_info.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_get_account_info.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_get_payment.pb.dart b/frontend/app/lib/pb/rpc_get_payment.pb.dart
index 526b590..65116df 100644
--- a/frontend/app/lib/pb/rpc_get_payment.pb.dart
+++ b/frontend/app/lib/pb/rpc_get_payment.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'payment.pb.dart' as $3;
+import 'payment.pb.dart' as $30;
 
 class GetPaymentRequest extends $pb.GeneratedMessage {
   factory GetPaymentRequest({
@@ -68,7 +68,7 @@ class GetPaymentRequest extends $pb.GeneratedMessage {
 
 class GetPaymentResponse extends $pb.GeneratedMessage {
   factory GetPaymentResponse({
-    $3.Payment? payment,
+    $30.Payment? payment,
   }) {
     final $result = create();
     if (payment != null) {
@@ -81,7 +81,7 @@ class GetPaymentResponse extends $pb.GeneratedMessage {
   factory GetPaymentResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetPaymentResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..aOM<$3.Payment>(1, _omitFieldNames ? '' : 'payment', subBuilder: $3.Payment.create)
+    ..aOM<$30.Payment>(1, _omitFieldNames ? '' : 'payment', subBuilder: $30.Payment.create)
     ..hasRequiredFields = false
   ;
 
@@ -107,15 +107,15 @@ class GetPaymentResponse extends $pb.GeneratedMessage {
   static GetPaymentResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $3.Payment get payment => $_getN(0);
+  $30.Payment get payment => $_getN(0);
   @$pb.TagNumber(1)
-  set payment($3.Payment v) { setField(1, v); }
+  set payment($30.Payment v) { setField(1, v); }
   @$pb.TagNumber(1)
   $core.bool hasPayment() => $_has(0);
   @$pb.TagNumber(1)
   void clearPayment() => clearField(1);
   @$pb.TagNumber(1)
-  $3.Payment ensurePayment() => $_ensure(0);
+  $30.Payment ensurePayment() => $_ensure(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_get_payment.pbserver.dart b/frontend/app/lib/pb/rpc_get_payment.pbserver.dart
deleted file mode 100644
index b758155..0000000
--- a/frontend/app/lib/pb/rpc_get_payment.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_get_payment.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_get_payment.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_get_person.pb.dart b/frontend/app/lib/pb/rpc_get_person.pb.dart
index 5b5badf..153be84 100644
--- a/frontend/app/lib/pb/rpc_get_person.pb.dart
+++ b/frontend/app/lib/pb/rpc_get_person.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'person.pb.dart' as $4;
+import 'person.pb.dart' as $31;
 
 class GetPersonRequest extends $pb.GeneratedMessage {
   factory GetPersonRequest({
@@ -68,7 +68,7 @@ class GetPersonRequest extends $pb.GeneratedMessage {
 
 class GetPersonResponse extends $pb.GeneratedMessage {
   factory GetPersonResponse({
-    $4.Person? person,
+    $31.Person? person,
   }) {
     final $result = create();
     if (person != null) {
@@ -81,7 +81,7 @@ class GetPersonResponse extends $pb.GeneratedMessage {
   factory GetPersonResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'GetPersonResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..aOM<$4.Person>(1, _omitFieldNames ? '' : 'person', subBuilder: $4.Person.create)
+    ..aOM<$31.Person>(1, _omitFieldNames ? '' : 'person', subBuilder: $31.Person.create)
     ..hasRequiredFields = false
   ;
 
@@ -107,15 +107,15 @@ class GetPersonResponse extends $pb.GeneratedMessage {
   static GetPersonResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $4.Person get person => $_getN(0);
+  $31.Person get person => $_getN(0);
   @$pb.TagNumber(1)
-  set person($4.Person v) { setField(1, v); }
+  set person($31.Person v) { setField(1, v); }
   @$pb.TagNumber(1)
   $core.bool hasPerson() => $_has(0);
   @$pb.TagNumber(1)
   void clearPerson() => clearField(1);
   @$pb.TagNumber(1)
-  $4.Person ensurePerson() => $_ensure(0);
+  $31.Person ensurePerson() => $_ensure(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_get_person.pbserver.dart b/frontend/app/lib/pb/rpc_get_person.pbserver.dart
deleted file mode 100644
index d182110..0000000
--- a/frontend/app/lib/pb/rpc_get_person.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_get_person.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_get_person.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_list_account_info.pb.dart b/frontend/app/lib/pb/rpc_list_account_info.pb.dart
index 9e12410..26e2431 100644
--- a/frontend/app/lib/pb/rpc_list_account_info.pb.dart
+++ b/frontend/app/lib/pb/rpc_list_account_info.pb.dart
@@ -13,7 +13,7 @@ import 'dart:core' as $core;
 
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'account_info.pb.dart' as $1;
+import 'account_info.pb.dart' as $28;
 
 class ListAccountInfoRequest extends $pb.GeneratedMessage {
   factory ListAccountInfoRequest({
@@ -81,7 +81,7 @@ class ListAccountInfoRequest extends $pb.GeneratedMessage {
 
 class ListAccountInfoResponse extends $pb.GeneratedMessage {
   factory ListAccountInfoResponse({
-    $core.Iterable<$1.AccountInfo>? accountInfo,
+    $core.Iterable<$28.AccountInfo>? accountInfo,
   }) {
     final $result = create();
     if (accountInfo != null) {
@@ -94,7 +94,7 @@ class ListAccountInfoResponse extends $pb.GeneratedMessage {
   factory ListAccountInfoResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListAccountInfoResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..pc<$1.AccountInfo>(1, _omitFieldNames ? '' : 'accountInfo', $pb.PbFieldType.PM, subBuilder: $1.AccountInfo.create)
+    ..pc<$28.AccountInfo>(1, _omitFieldNames ? '' : 'accountInfo', $pb.PbFieldType.PM, subBuilder: $28.AccountInfo.create)
     ..hasRequiredFields = false
   ;
 
@@ -120,7 +120,7 @@ class ListAccountInfoResponse extends $pb.GeneratedMessage {
   static ListAccountInfoResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $core.List<$1.AccountInfo> get accountInfo => $_getList(0);
+  $core.List<$28.AccountInfo> get accountInfo => $_getList(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_list_account_info.pbserver.dart b/frontend/app/lib/pb/rpc_list_account_info.pbserver.dart
deleted file mode 100644
index c519635..0000000
--- a/frontend/app/lib/pb/rpc_list_account_info.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_list_account_info.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_list_account_info.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_list_accounts.pb.dart b/frontend/app/lib/pb/rpc_list_accounts.pb.dart
index 9dd20a2..341c749 100644
--- a/frontend/app/lib/pb/rpc_list_accounts.pb.dart
+++ b/frontend/app/lib/pb/rpc_list_accounts.pb.dart
@@ -13,7 +13,7 @@ import 'dart:core' as $core;
 
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'account.pb.dart' as $2;
+import 'account.pb.dart' as $29;
 
 class ListAccountsRequest extends $pb.GeneratedMessage {
   factory ListAccountsRequest({
@@ -81,7 +81,7 @@ class ListAccountsRequest extends $pb.GeneratedMessage {
 
 class ListAccountsResponse extends $pb.GeneratedMessage {
   factory ListAccountsResponse({
-    $core.Iterable<$2.Account>? accounts,
+    $core.Iterable<$29.Account>? accounts,
   }) {
     final $result = create();
     if (accounts != null) {
@@ -94,7 +94,7 @@ class ListAccountsResponse extends $pb.GeneratedMessage {
   factory ListAccountsResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListAccountsResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..pc<$2.Account>(1, _omitFieldNames ? '' : 'accounts', $pb.PbFieldType.PM, subBuilder: $2.Account.create)
+    ..pc<$29.Account>(1, _omitFieldNames ? '' : 'accounts', $pb.PbFieldType.PM, subBuilder: $29.Account.create)
     ..hasRequiredFields = false
   ;
 
@@ -120,7 +120,7 @@ class ListAccountsResponse extends $pb.GeneratedMessage {
   static ListAccountsResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $core.List<$2.Account> get accounts => $_getList(0);
+  $core.List<$29.Account> get accounts => $_getList(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_list_accounts.pbserver.dart b/frontend/app/lib/pb/rpc_list_accounts.pbserver.dart
deleted file mode 100644
index 8182a04..0000000
--- a/frontend/app/lib/pb/rpc_list_accounts.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_list_accounts.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_list_accounts.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_list_payments.pb.dart b/frontend/app/lib/pb/rpc_list_payments.pb.dart
index a7110a6..2478efc 100644
--- a/frontend/app/lib/pb/rpc_list_payments.pb.dart
+++ b/frontend/app/lib/pb/rpc_list_payments.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'payment.pb.dart' as $3;
+import 'payment.pb.dart' as $30;
 
 class ListPaymentsRequest extends $pb.GeneratedMessage {
   factory ListPaymentsRequest({
@@ -68,7 +68,7 @@ class ListPaymentsRequest extends $pb.GeneratedMessage {
 
 class ListPaymentsResponse extends $pb.GeneratedMessage {
   factory ListPaymentsResponse({
-    $core.Iterable<$3.Payment>? payments,
+    $core.Iterable<$30.Payment>? payments,
   }) {
     final $result = create();
     if (payments != null) {
@@ -81,7 +81,7 @@ class ListPaymentsResponse extends $pb.GeneratedMessage {
   factory ListPaymentsResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListPaymentsResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..pc<$3.Payment>(1, _omitFieldNames ? '' : 'payments', $pb.PbFieldType.PM, subBuilder: $3.Payment.create)
+    ..pc<$30.Payment>(1, _omitFieldNames ? '' : 'payments', $pb.PbFieldType.PM, subBuilder: $30.Payment.create)
     ..hasRequiredFields = false
   ;
 
@@ -107,7 +107,7 @@ class ListPaymentsResponse extends $pb.GeneratedMessage {
   static ListPaymentsResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $core.List<$3.Payment> get payments => $_getList(0);
+  $core.List<$30.Payment> get payments => $_getList(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_list_payments.pbserver.dart b/frontend/app/lib/pb/rpc_list_payments.pbserver.dart
deleted file mode 100644
index 3447e3d..0000000
--- a/frontend/app/lib/pb/rpc_list_payments.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_list_payments.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_list_payments.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_list_persons.pb.dart b/frontend/app/lib/pb/rpc_list_persons.pb.dart
index bfac765..fe13d8b 100644
--- a/frontend/app/lib/pb/rpc_list_persons.pb.dart
+++ b/frontend/app/lib/pb/rpc_list_persons.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'person.pb.dart' as $4;
+import 'person.pb.dart' as $31;
 
 class ListPersonsRequest extends $pb.GeneratedMessage {
   factory ListPersonsRequest({
@@ -68,7 +68,7 @@ class ListPersonsRequest extends $pb.GeneratedMessage {
 
 class ListPersonsResponse extends $pb.GeneratedMessage {
   factory ListPersonsResponse({
-    $core.Iterable<$4.Person>? persons,
+    $core.Iterable<$31.Person>? persons,
   }) {
     final $result = create();
     if (persons != null) {
@@ -81,7 +81,7 @@ class ListPersonsResponse extends $pb.GeneratedMessage {
   factory ListPersonsResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListPersonsResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..pc<$4.Person>(1, _omitFieldNames ? '' : 'persons', $pb.PbFieldType.PM, subBuilder: $4.Person.create)
+    ..pc<$31.Person>(1, _omitFieldNames ? '' : 'persons', $pb.PbFieldType.PM, subBuilder: $31.Person.create)
     ..hasRequiredFields = false
   ;
 
@@ -107,7 +107,7 @@ class ListPersonsResponse extends $pb.GeneratedMessage {
   static ListPersonsResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $core.List<$4.Person> get persons => $_getList(0);
+  $core.List<$31.Person> get persons => $_getList(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_list_persons.pbserver.dart b/frontend/app/lib/pb/rpc_list_persons.pbserver.dart
deleted file mode 100644
index f7e01f9..0000000
--- a/frontend/app/lib/pb/rpc_list_persons.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_list_persons.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_list_persons.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pb.dart b/frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pb.dart
index 61fbff1..90a2f62 100644
--- a/frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pb.dart
+++ b/frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'returns_log.pb.dart' as $5;
+import 'returns_log.pb.dart' as $32;
 
 class ListReturnsLogRequest extends $pb.GeneratedMessage {
   factory ListReturnsLogRequest({
@@ -68,7 +68,7 @@ class ListReturnsLogRequest extends $pb.GeneratedMessage {
 
 class ListReturnsLogResponse extends $pb.GeneratedMessage {
   factory ListReturnsLogResponse({
-    $core.Iterable<$5.ReturnsLog>? returnsLog,
+    $core.Iterable<$32.ReturnsLog>? returnsLog,
   }) {
     final $result = create();
     if (returnsLog != null) {
@@ -81,7 +81,7 @@ class ListReturnsLogResponse extends $pb.GeneratedMessage {
   factory ListReturnsLogResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListReturnsLogResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..pc<$5.ReturnsLog>(1, _omitFieldNames ? '' : 'returnsLog', $pb.PbFieldType.PM, subBuilder: $5.ReturnsLog.create)
+    ..pc<$32.ReturnsLog>(1, _omitFieldNames ? '' : 'returnsLog', $pb.PbFieldType.PM, subBuilder: $32.ReturnsLog.create)
     ..hasRequiredFields = false
   ;
 
@@ -107,7 +107,7 @@ class ListReturnsLogResponse extends $pb.GeneratedMessage {
   static ListReturnsLogResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $core.List<$5.ReturnsLog> get returnsLog => $_getList(0);
+  $core.List<$32.ReturnsLog> get returnsLog => $_getList(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pbserver.dart b/frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pbserver.dart
deleted file mode 100644
index 8498af0..0000000
--- a/frontend/app/lib/pb/rpc_list_returns_log_by_person_id.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_list_returns_log_by_person_id.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_list_returns_log_by_person_id.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_list_sessions.pb.dart b/frontend/app/lib/pb/rpc_list_sessions.pb.dart
index 1a9f5af..1856def 100644
--- a/frontend/app/lib/pb/rpc_list_sessions.pb.dart
+++ b/frontend/app/lib/pb/rpc_list_sessions.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'session.pb.dart' as $6;
+import 'session.pb.dart' as $33;
 
 class ListSessionsRequest extends $pb.GeneratedMessage {
   factory ListSessionsRequest({
@@ -68,7 +68,7 @@ class ListSessionsRequest extends $pb.GeneratedMessage {
 
 class ListSessionsResponse extends $pb.GeneratedMessage {
   factory ListSessionsResponse({
-    $core.Iterable<$6.Session>? sessions,
+    $core.Iterable<$33.Session>? sessions,
   }) {
     final $result = create();
     if (sessions != null) {
@@ -81,7 +81,7 @@ class ListSessionsResponse extends $pb.GeneratedMessage {
   factory ListSessionsResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'ListSessionsResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..pc<$6.Session>(1, _omitFieldNames ? '' : 'sessions', $pb.PbFieldType.PM, subBuilder: $6.Session.create)
+    ..pc<$33.Session>(1, _omitFieldNames ? '' : 'sessions', $pb.PbFieldType.PM, subBuilder: $33.Session.create)
     ..hasRequiredFields = false
   ;
 
@@ -107,7 +107,7 @@ class ListSessionsResponse extends $pb.GeneratedMessage {
   static ListSessionsResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $core.List<$6.Session> get sessions => $_getList(0);
+  $core.List<$33.Session> get sessions => $_getList(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_list_sessions.pbserver.dart b/frontend/app/lib/pb/rpc_list_sessions.pbserver.dart
deleted file mode 100644
index e4bcfda..0000000
--- a/frontend/app/lib/pb/rpc_list_sessions.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_list_sessions.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_list_sessions.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_login.pb.dart b/frontend/app/lib/pb/rpc_login.pb.dart
index 30ded55..1b2c155 100644
--- a/frontend/app/lib/pb/rpc_login.pb.dart
+++ b/frontend/app/lib/pb/rpc_login.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'google/protobuf/timestamp.pb.dart' as $0;
+import 'google/protobuf/timestamp.pb.dart' as $27;
 
 class LoginRequest extends $pb.GeneratedMessage {
   factory LoginRequest({
@@ -84,9 +84,9 @@ class LoginResponse extends $pb.GeneratedMessage {
   factory LoginResponse({
     $core.String? sessionId,
     $core.String? accessToken,
-    $0.Timestamp? accessTokenExpiresAt,
+    $27.Timestamp? accessTokenExpiresAt,
     $core.String? refreshToken,
-    $0.Timestamp? refreshTokenExpiresAt,
+    $27.Timestamp? refreshTokenExpiresAt,
     $fixnum.Int64? accountId,
   }) {
     final $result = create();
@@ -117,9 +117,9 @@ class LoginResponse extends $pb.GeneratedMessage {
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'LoginResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
     ..aOS(1, _omitFieldNames ? '' : 'sessionId')
     ..aOS(2, _omitFieldNames ? '' : 'accessToken')
-    ..aOM<$0.Timestamp>(3, _omitFieldNames ? '' : 'accessTokenExpiresAt', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(3, _omitFieldNames ? '' : 'accessTokenExpiresAt', subBuilder: $27.Timestamp.create)
     ..aOS(4, _omitFieldNames ? '' : 'refreshToken')
-    ..aOM<$0.Timestamp>(5, _omitFieldNames ? '' : 'refreshTokenExpiresAt', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(5, _omitFieldNames ? '' : 'refreshTokenExpiresAt', subBuilder: $27.Timestamp.create)
     ..a<$fixnum.Int64>(6, _omitFieldNames ? '' : 'accountId', $pb.PbFieldType.OU6, defaultOrMaker: $fixnum.Int64.ZERO)
     ..hasRequiredFields = false
   ;
@@ -164,15 +164,15 @@ class LoginResponse extends $pb.GeneratedMessage {
   void clearAccessToken() => clearField(2);
 
   @$pb.TagNumber(3)
-  $0.Timestamp get accessTokenExpiresAt => $_getN(2);
+  $27.Timestamp get accessTokenExpiresAt => $_getN(2);
   @$pb.TagNumber(3)
-  set accessTokenExpiresAt($0.Timestamp v) { setField(3, v); }
+  set accessTokenExpiresAt($27.Timestamp v) { setField(3, v); }
   @$pb.TagNumber(3)
   $core.bool hasAccessTokenExpiresAt() => $_has(2);
   @$pb.TagNumber(3)
   void clearAccessTokenExpiresAt() => clearField(3);
   @$pb.TagNumber(3)
-  $0.Timestamp ensureAccessTokenExpiresAt() => $_ensure(2);
+  $27.Timestamp ensureAccessTokenExpiresAt() => $_ensure(2);
 
   @$pb.TagNumber(4)
   $core.String get refreshToken => $_getSZ(3);
@@ -184,15 +184,15 @@ class LoginResponse extends $pb.GeneratedMessage {
   void clearRefreshToken() => clearField(4);
 
   @$pb.TagNumber(5)
-  $0.Timestamp get refreshTokenExpiresAt => $_getN(4);
+  $27.Timestamp get refreshTokenExpiresAt => $_getN(4);
   @$pb.TagNumber(5)
-  set refreshTokenExpiresAt($0.Timestamp v) { setField(5, v); }
+  set refreshTokenExpiresAt($27.Timestamp v) { setField(5, v); }
   @$pb.TagNumber(5)
   $core.bool hasRefreshTokenExpiresAt() => $_has(4);
   @$pb.TagNumber(5)
   void clearRefreshTokenExpiresAt() => clearField(5);
   @$pb.TagNumber(5)
-  $0.Timestamp ensureRefreshTokenExpiresAt() => $_ensure(4);
+  $27.Timestamp ensureRefreshTokenExpiresAt() => $_ensure(4);
 
   @$pb.TagNumber(6)
   $fixnum.Int64 get accountId => $_getI64(5);
diff --git a/frontend/app/lib/pb/rpc_login.pbserver.dart b/frontend/app/lib/pb/rpc_login.pbserver.dart
deleted file mode 100644
index c90dce9..0000000
--- a/frontend/app/lib/pb/rpc_login.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_login.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_login.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_refresh_token.pb.dart b/frontend/app/lib/pb/rpc_refresh_token.pb.dart
index a7780c3..0011b5e 100644
--- a/frontend/app/lib/pb/rpc_refresh_token.pb.dart
+++ b/frontend/app/lib/pb/rpc_refresh_token.pb.dart
@@ -13,7 +13,7 @@ import 'dart:core' as $core;
 
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'google/protobuf/timestamp.pb.dart' as $0;
+import 'google/protobuf/timestamp.pb.dart' as $27;
 
 class RefreshTokenRequest extends $pb.GeneratedMessage {
   factory RefreshTokenRequest({
@@ -68,7 +68,7 @@ class RefreshTokenRequest extends $pb.GeneratedMessage {
 class RefreshTokenResponse extends $pb.GeneratedMessage {
   factory RefreshTokenResponse({
     $core.String? accessToken,
-    $0.Timestamp? accessTokenExpiresAt,
+    $27.Timestamp? accessTokenExpiresAt,
   }) {
     final $result = create();
     if (accessToken != null) {
@@ -85,7 +85,7 @@ class RefreshTokenResponse extends $pb.GeneratedMessage {
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'RefreshTokenResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
     ..aOS(1, _omitFieldNames ? '' : 'accessToken')
-    ..aOM<$0.Timestamp>(2, _omitFieldNames ? '' : 'accessTokenExpiresAt', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(2, _omitFieldNames ? '' : 'accessTokenExpiresAt', subBuilder: $27.Timestamp.create)
     ..hasRequiredFields = false
   ;
 
@@ -120,15 +120,15 @@ class RefreshTokenResponse extends $pb.GeneratedMessage {
   void clearAccessToken() => clearField(1);
 
   @$pb.TagNumber(2)
-  $0.Timestamp get accessTokenExpiresAt => $_getN(1);
+  $27.Timestamp get accessTokenExpiresAt => $_getN(1);
   @$pb.TagNumber(2)
-  set accessTokenExpiresAt($0.Timestamp v) { setField(2, v); }
+  set accessTokenExpiresAt($27.Timestamp v) { setField(2, v); }
   @$pb.TagNumber(2)
   $core.bool hasAccessTokenExpiresAt() => $_has(1);
   @$pb.TagNumber(2)
   void clearAccessTokenExpiresAt() => clearField(2);
   @$pb.TagNumber(2)
-  $0.Timestamp ensureAccessTokenExpiresAt() => $_ensure(1);
+  $27.Timestamp ensureAccessTokenExpiresAt() => $_ensure(1);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_refresh_token.pbserver.dart b/frontend/app/lib/pb/rpc_refresh_token.pbserver.dart
deleted file mode 100644
index df1bd59..0000000
--- a/frontend/app/lib/pb/rpc_refresh_token.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_refresh_token.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_refresh_token.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_update_account.pb.dart b/frontend/app/lib/pb/rpc_update_account.pb.dart
index 049177b..e1b01d8 100644
--- a/frontend/app/lib/pb/rpc_update_account.pb.dart
+++ b/frontend/app/lib/pb/rpc_update_account.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'account.pb.dart' as $2;
+import 'account.pb.dart' as $29;
 
 class UpdateAccountRequest extends $pb.GeneratedMessage {
   factory UpdateAccountRequest({
@@ -96,7 +96,7 @@ class UpdateAccountRequest extends $pb.GeneratedMessage {
 
 class UpdateAccountResponse extends $pb.GeneratedMessage {
   factory UpdateAccountResponse({
-    $2.Account? account,
+    $29.Account? account,
   }) {
     final $result = create();
     if (account != null) {
@@ -109,7 +109,7 @@ class UpdateAccountResponse extends $pb.GeneratedMessage {
   factory UpdateAccountResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UpdateAccountResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..aOM<$2.Account>(1, _omitFieldNames ? '' : 'account', subBuilder: $2.Account.create)
+    ..aOM<$29.Account>(1, _omitFieldNames ? '' : 'account', subBuilder: $29.Account.create)
     ..hasRequiredFields = false
   ;
 
@@ -135,15 +135,15 @@ class UpdateAccountResponse extends $pb.GeneratedMessage {
   static UpdateAccountResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $2.Account get account => $_getN(0);
+  $29.Account get account => $_getN(0);
   @$pb.TagNumber(1)
-  set account($2.Account v) { setField(1, v); }
+  set account($29.Account v) { setField(1, v); }
   @$pb.TagNumber(1)
   $core.bool hasAccount() => $_has(0);
   @$pb.TagNumber(1)
   void clearAccount() => clearField(1);
   @$pb.TagNumber(1)
-  $2.Account ensureAccount() => $_ensure(0);
+  $29.Account ensureAccount() => $_ensure(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_update_account.pbserver.dart b/frontend/app/lib/pb/rpc_update_account.pbserver.dart
deleted file mode 100644
index 8268e1e..0000000
--- a/frontend/app/lib/pb/rpc_update_account.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_update_account.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_update_account.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_update_account_info.pb.dart b/frontend/app/lib/pb/rpc_update_account_info.pb.dart
index f7066bf..e6199e9 100644
--- a/frontend/app/lib/pb/rpc_update_account_info.pb.dart
+++ b/frontend/app/lib/pb/rpc_update_account_info.pb.dart
@@ -14,8 +14,8 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'account_info.pb.dart' as $1;
-import 'google/protobuf/timestamp.pb.dart' as $0;
+import 'account_info.pb.dart' as $28;
+import 'google/protobuf/timestamp.pb.dart' as $27;
 
 class UpdateAccountInfoRequest extends $pb.GeneratedMessage {
   factory UpdateAccountInfoRequest({
@@ -27,7 +27,7 @@ class UpdateAccountInfoRequest extends $pb.GeneratedMessage {
     $core.String? zip,
     $core.String? country,
     $core.String? phone,
-    $0.Timestamp? birthday,
+    $27.Timestamp? birthday,
   }) {
     final $result = create();
     if (accountId != null) {
@@ -72,7 +72,7 @@ class UpdateAccountInfoRequest extends $pb.GeneratedMessage {
     ..aOS(8, _omitFieldNames ? '' : 'zip')
     ..aOS(9, _omitFieldNames ? '' : 'country')
     ..aOS(10, _omitFieldNames ? '' : 'phone')
-    ..aOM<$0.Timestamp>(11, _omitFieldNames ? '' : 'birthday', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(11, _omitFieldNames ? '' : 'birthday', subBuilder: $27.Timestamp.create)
     ..hasRequiredFields = false
   ;
 
@@ -170,20 +170,20 @@ class UpdateAccountInfoRequest extends $pb.GeneratedMessage {
   void clearPhone() => clearField(10);
 
   @$pb.TagNumber(11)
-  $0.Timestamp get birthday => $_getN(8);
+  $27.Timestamp get birthday => $_getN(8);
   @$pb.TagNumber(11)
-  set birthday($0.Timestamp v) { setField(11, v); }
+  set birthday($27.Timestamp v) { setField(11, v); }
   @$pb.TagNumber(11)
   $core.bool hasBirthday() => $_has(8);
   @$pb.TagNumber(11)
   void clearBirthday() => clearField(11);
   @$pb.TagNumber(11)
-  $0.Timestamp ensureBirthday() => $_ensure(8);
+  $27.Timestamp ensureBirthday() => $_ensure(8);
 }
 
 class UpdateAccountInfoResponse extends $pb.GeneratedMessage {
   factory UpdateAccountInfoResponse({
-    $1.AccountInfo? accountInfo,
+    $28.AccountInfo? accountInfo,
   }) {
     final $result = create();
     if (accountInfo != null) {
@@ -196,7 +196,7 @@ class UpdateAccountInfoResponse extends $pb.GeneratedMessage {
   factory UpdateAccountInfoResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UpdateAccountInfoResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..aOM<$1.AccountInfo>(1, _omitFieldNames ? '' : 'accountInfo', subBuilder: $1.AccountInfo.create)
+    ..aOM<$28.AccountInfo>(1, _omitFieldNames ? '' : 'accountInfo', subBuilder: $28.AccountInfo.create)
     ..hasRequiredFields = false
   ;
 
@@ -222,15 +222,15 @@ class UpdateAccountInfoResponse extends $pb.GeneratedMessage {
   static UpdateAccountInfoResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $1.AccountInfo get accountInfo => $_getN(0);
+  $28.AccountInfo get accountInfo => $_getN(0);
   @$pb.TagNumber(1)
-  set accountInfo($1.AccountInfo v) { setField(1, v); }
+  set accountInfo($28.AccountInfo v) { setField(1, v); }
   @$pb.TagNumber(1)
   $core.bool hasAccountInfo() => $_has(0);
   @$pb.TagNumber(1)
   void clearAccountInfo() => clearField(1);
   @$pb.TagNumber(1)
-  $1.AccountInfo ensureAccountInfo() => $_ensure(0);
+  $28.AccountInfo ensureAccountInfo() => $_ensure(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_update_account_info.pbserver.dart b/frontend/app/lib/pb/rpc_update_account_info.pbserver.dart
deleted file mode 100644
index 181645c..0000000
--- a/frontend/app/lib/pb/rpc_update_account_info.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_update_account_info.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_update_account_info.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_update_account_privacy.pb.dart b/frontend/app/lib/pb/rpc_update_account_privacy.pb.dart
index 68719c9..4f2ecfd 100644
--- a/frontend/app/lib/pb/rpc_update_account_privacy.pb.dart
+++ b/frontend/app/lib/pb/rpc_update_account_privacy.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'account_info.pb.dart' as $1;
+import 'account_info.pb.dart' as $28;
 
 class UpdateAccountPrivacyRequest extends $pb.GeneratedMessage {
   factory UpdateAccountPrivacyRequest({
@@ -82,7 +82,7 @@ class UpdateAccountPrivacyRequest extends $pb.GeneratedMessage {
 
 class UpdateAccountPrivacyResponse extends $pb.GeneratedMessage {
   factory UpdateAccountPrivacyResponse({
-    $1.AccountInfo? accountInfo,
+    $28.AccountInfo? accountInfo,
   }) {
     final $result = create();
     if (accountInfo != null) {
@@ -95,7 +95,7 @@ class UpdateAccountPrivacyResponse extends $pb.GeneratedMessage {
   factory UpdateAccountPrivacyResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UpdateAccountPrivacyResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..aOM<$1.AccountInfo>(1, _omitFieldNames ? '' : 'accountInfo', subBuilder: $1.AccountInfo.create)
+    ..aOM<$28.AccountInfo>(1, _omitFieldNames ? '' : 'accountInfo', subBuilder: $28.AccountInfo.create)
     ..hasRequiredFields = false
   ;
 
@@ -121,15 +121,15 @@ class UpdateAccountPrivacyResponse extends $pb.GeneratedMessage {
   static UpdateAccountPrivacyResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $1.AccountInfo get accountInfo => $_getN(0);
+  $28.AccountInfo get accountInfo => $_getN(0);
   @$pb.TagNumber(1)
-  set accountInfo($1.AccountInfo v) { setField(1, v); }
+  set accountInfo($28.AccountInfo v) { setField(1, v); }
   @$pb.TagNumber(1)
   $core.bool hasAccountInfo() => $_has(0);
   @$pb.TagNumber(1)
   void clearAccountInfo() => clearField(1);
   @$pb.TagNumber(1)
-  $1.AccountInfo ensureAccountInfo() => $_ensure(0);
+  $28.AccountInfo ensureAccountInfo() => $_ensure(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_update_account_privacy.pbserver.dart b/frontend/app/lib/pb/rpc_update_account_privacy.pbserver.dart
deleted file mode 100644
index 2b7d3b6..0000000
--- a/frontend/app/lib/pb/rpc_update_account_privacy.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_update_account_privacy.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_update_account_privacy.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_update_payment.pb.dart b/frontend/app/lib/pb/rpc_update_payment.pb.dart
index 42a8739..09c0acc 100644
--- a/frontend/app/lib/pb/rpc_update_payment.pb.dart
+++ b/frontend/app/lib/pb/rpc_update_payment.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'payment.pb.dart' as $3;
+import 'payment.pb.dart' as $30;
 
 class UpdatePaymentRequest extends $pb.GeneratedMessage {
   factory UpdatePaymentRequest({
@@ -180,7 +180,7 @@ class UpdatePaymentRequest extends $pb.GeneratedMessage {
 
 class UpdatePaymentResponse extends $pb.GeneratedMessage {
   factory UpdatePaymentResponse({
-    $3.Payment? payment,
+    $30.Payment? payment,
   }) {
     final $result = create();
     if (payment != null) {
@@ -193,7 +193,7 @@ class UpdatePaymentResponse extends $pb.GeneratedMessage {
   factory UpdatePaymentResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UpdatePaymentResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..aOM<$3.Payment>(1, _omitFieldNames ? '' : 'payment', subBuilder: $3.Payment.create)
+    ..aOM<$30.Payment>(1, _omitFieldNames ? '' : 'payment', subBuilder: $30.Payment.create)
     ..hasRequiredFields = false
   ;
 
@@ -219,15 +219,15 @@ class UpdatePaymentResponse extends $pb.GeneratedMessage {
   static UpdatePaymentResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $3.Payment get payment => $_getN(0);
+  $30.Payment get payment => $_getN(0);
   @$pb.TagNumber(1)
-  set payment($3.Payment v) { setField(1, v); }
+  set payment($30.Payment v) { setField(1, v); }
   @$pb.TagNumber(1)
   $core.bool hasPayment() => $_has(0);
   @$pb.TagNumber(1)
   void clearPayment() => clearField(1);
   @$pb.TagNumber(1)
-  $3.Payment ensurePayment() => $_ensure(0);
+  $30.Payment ensurePayment() => $_ensure(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_update_payment.pbserver.dart b/frontend/app/lib/pb/rpc_update_payment.pbserver.dart
deleted file mode 100644
index b3179bb..0000000
--- a/frontend/app/lib/pb/rpc_update_payment.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_update_payment.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_update_payment.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_update_person.pb.dart b/frontend/app/lib/pb/rpc_update_person.pb.dart
index d904eba..146ffb9 100644
--- a/frontend/app/lib/pb/rpc_update_person.pb.dart
+++ b/frontend/app/lib/pb/rpc_update_person.pb.dart
@@ -14,8 +14,8 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'google/protobuf/timestamp.pb.dart' as $0;
-import 'person.pb.dart' as $4;
+import 'google/protobuf/timestamp.pb.dart' as $27;
+import 'person.pb.dart' as $31;
 
 class UpdatePersonRequest extends $pb.GeneratedMessage {
   factory UpdatePersonRequest({
@@ -26,7 +26,7 @@ class UpdatePersonRequest extends $pb.GeneratedMessage {
     $core.String? city,
     $core.String? zip,
     $core.String? country,
-    $0.Timestamp? birthday,
+    $27.Timestamp? birthday,
   }) {
     final $result = create();
     if (id != null) {
@@ -67,7 +67,7 @@ class UpdatePersonRequest extends $pb.GeneratedMessage {
     ..aOS(5, _omitFieldNames ? '' : 'city')
     ..aOS(6, _omitFieldNames ? '' : 'zip')
     ..aOS(7, _omitFieldNames ? '' : 'country')
-    ..aOM<$0.Timestamp>(8, _omitFieldNames ? '' : 'birthday', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(8, _omitFieldNames ? '' : 'birthday', subBuilder: $27.Timestamp.create)
     ..hasRequiredFields = false
   ;
 
@@ -156,20 +156,20 @@ class UpdatePersonRequest extends $pb.GeneratedMessage {
   void clearCountry() => clearField(7);
 
   @$pb.TagNumber(8)
-  $0.Timestamp get birthday => $_getN(7);
+  $27.Timestamp get birthday => $_getN(7);
   @$pb.TagNumber(8)
-  set birthday($0.Timestamp v) { setField(8, v); }
+  set birthday($27.Timestamp v) { setField(8, v); }
   @$pb.TagNumber(8)
   $core.bool hasBirthday() => $_has(7);
   @$pb.TagNumber(8)
   void clearBirthday() => clearField(8);
   @$pb.TagNumber(8)
-  $0.Timestamp ensureBirthday() => $_ensure(7);
+  $27.Timestamp ensureBirthday() => $_ensure(7);
 }
 
 class UpdatePersonResponse extends $pb.GeneratedMessage {
   factory UpdatePersonResponse({
-    $4.Person? person,
+    $31.Person? person,
   }) {
     final $result = create();
     if (person != null) {
@@ -182,7 +182,7 @@ class UpdatePersonResponse extends $pb.GeneratedMessage {
   factory UpdatePersonResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UpdatePersonResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..aOM<$4.Person>(1, _omitFieldNames ? '' : 'person', subBuilder: $4.Person.create)
+    ..aOM<$31.Person>(1, _omitFieldNames ? '' : 'person', subBuilder: $31.Person.create)
     ..hasRequiredFields = false
   ;
 
@@ -208,15 +208,15 @@ class UpdatePersonResponse extends $pb.GeneratedMessage {
   static UpdatePersonResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $4.Person get person => $_getN(0);
+  $31.Person get person => $_getN(0);
   @$pb.TagNumber(1)
-  set person($4.Person v) { setField(1, v); }
+  set person($31.Person v) { setField(1, v); }
   @$pb.TagNumber(1)
   $core.bool hasPerson() => $_has(0);
   @$pb.TagNumber(1)
   void clearPerson() => clearField(1);
   @$pb.TagNumber(1)
-  $4.Person ensurePerson() => $_ensure(0);
+  $31.Person ensurePerson() => $_ensure(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_update_person.pbserver.dart b/frontend/app/lib/pb/rpc_update_person.pbserver.dart
deleted file mode 100644
index 784dbe1..0000000
--- a/frontend/app/lib/pb/rpc_update_person.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_update_person.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_update_person.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_upload_document.pb.dart b/frontend/app/lib/pb/rpc_upload_document.pb.dart
index d3cec63..652df8d 100644
--- a/frontend/app/lib/pb/rpc_upload_document.pb.dart
+++ b/frontend/app/lib/pb/rpc_upload_document.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'document.pb.dart' as $7;
+import 'document.pb.dart' as $34;
 
 class UploadDocumentRequest extends $pb.GeneratedMessage {
   factory UploadDocumentRequest({
@@ -96,7 +96,7 @@ class UploadDocumentRequest extends $pb.GeneratedMessage {
 
 class UploadDocumentResponse extends $pb.GeneratedMessage {
   factory UploadDocumentResponse({
-    $7.Document? document,
+    $34.Document? document,
   }) {
     final $result = create();
     if (document != null) {
@@ -109,7 +109,7 @@ class UploadDocumentResponse extends $pb.GeneratedMessage {
   factory UploadDocumentResponse.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
 
   static final $pb.BuilderInfo _i = $pb.BuilderInfo(_omitMessageNames ? '' : 'UploadDocumentResponse', package: const $pb.PackageName(_omitMessageNames ? '' : 'pb'), createEmptyInstance: create)
-    ..aOM<$7.Document>(1, _omitFieldNames ? '' : 'document', subBuilder: $7.Document.create)
+    ..aOM<$34.Document>(1, _omitFieldNames ? '' : 'document', subBuilder: $34.Document.create)
     ..hasRequiredFields = false
   ;
 
@@ -135,15 +135,15 @@ class UploadDocumentResponse extends $pb.GeneratedMessage {
   static UploadDocumentResponse? _defaultInstance;
 
   @$pb.TagNumber(1)
-  $7.Document get document => $_getN(0);
+  $34.Document get document => $_getN(0);
   @$pb.TagNumber(1)
-  set document($7.Document v) { setField(1, v); }
+  set document($34.Document v) { setField(1, v); }
   @$pb.TagNumber(1)
   $core.bool hasDocument() => $_has(0);
   @$pb.TagNumber(1)
   void clearDocument() => clearField(1);
   @$pb.TagNumber(1)
-  $7.Document ensureDocument() => $_ensure(0);
+  $34.Document ensureDocument() => $_ensure(0);
 }
 
 
diff --git a/frontend/app/lib/pb/rpc_upload_document.pbserver.dart b/frontend/app/lib/pb/rpc_upload_document.pbserver.dart
deleted file mode 100644
index 437b306..0000000
--- a/frontend/app/lib/pb/rpc_upload_document.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_upload_document.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_upload_document.pb.dart';
-
diff --git a/frontend/app/lib/pb/rpc_verify_email.pbserver.dart b/frontend/app/lib/pb/rpc_verify_email.pbserver.dart
deleted file mode 100644
index 2c1e023..0000000
--- a/frontend/app/lib/pb/rpc_verify_email.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: rpc_verify_email.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'rpc_verify_email.pb.dart';
-
diff --git a/frontend/app/lib/pb/service_df.pb.dart b/frontend/app/lib/pb/service_df.pb.dart
index 6ee0f7a..7ebc5be 100644
--- a/frontend/app/lib/pb/service_df.pb.dart
+++ b/frontend/app/lib/pb/service_df.pb.dart
@@ -9,123 +9,5 @@
 // ignore_for_file: non_constant_identifier_names, prefer_final_fields
 // ignore_for_file: unnecessary_import, unnecessary_this, unused_import
 
-import 'dart:async' as $async;
 import 'dart:core' as $core;
 
-import 'package:protobuf/protobuf.dart' as $pb;
-
-import 'rpc_block_session.pb.dart' as $11;
-import 'rpc_create_account.pb.dart' as $14;
-import 'rpc_create_account_info.pb.dart' as $18;
-import 'rpc_create_payment.pb.dart' as $26;
-import 'rpc_create_person.pb.dart' as $21;
-import 'rpc_delete_document.pb.dart' as $33;
-import 'rpc_delete_payment.pb.dart' as $28;
-import 'rpc_delete_person.pb.dart' as $24;
-import 'rpc_get_account.pb.dart' as $12;
-import 'rpc_get_account_info.pb.dart' as $16;
-import 'rpc_get_payment.pb.dart' as $27;
-import 'rpc_get_person.pb.dart' as $23;
-import 'rpc_list_account_info.pb.dart' as $17;
-import 'rpc_list_accounts.pb.dart' as $13;
-import 'rpc_list_payments.pb.dart' as $29;
-import 'rpc_list_persons.pb.dart' as $25;
-import 'rpc_list_returns_log_by_person_id.pb.dart' as $31;
-import 'rpc_list_sessions.pb.dart' as $10;
-import 'rpc_login.pb.dart' as $8;
-import 'rpc_refresh_token.pb.dart' as $9;
-import 'rpc_update_account.pb.dart' as $15;
-import 'rpc_update_account_info.pb.dart' as $19;
-import 'rpc_update_account_privacy.pb.dart' as $20;
-import 'rpc_update_payment.pb.dart' as $30;
-import 'rpc_update_person.pb.dart' as $22;
-import 'rpc_upload_document.pb.dart' as $32;
-import 'rpc_verify_email.pb.dart' as $34;
-
-class dfApi {
-  $pb.RpcClient _client;
-  dfApi(this._client);
-
-  $async.Future<$8.LoginResponse> login($pb.ClientContext? ctx, $8.LoginRequest request) =>
-    _client.invoke<$8.LoginResponse>(ctx, 'df', 'Login', request, $8.LoginResponse())
-  ;
-  $async.Future<$9.RefreshTokenResponse> refreshToken($pb.ClientContext? ctx, $9.RefreshTokenRequest request) =>
-    _client.invoke<$9.RefreshTokenResponse>(ctx, 'df', 'RefreshToken', request, $9.RefreshTokenResponse())
-  ;
-  $async.Future<$10.ListSessionsResponse> listSessions($pb.ClientContext? ctx, $10.ListSessionsRequest request) =>
-    _client.invoke<$10.ListSessionsResponse>(ctx, 'df', 'ListSessions', request, $10.ListSessionsResponse())
-  ;
-  $async.Future<$11.BlockSessionResponse> blockSession($pb.ClientContext? ctx, $11.BlockSessionRequest request) =>
-    _client.invoke<$11.BlockSessionResponse>(ctx, 'df', 'BlockSession', request, $11.BlockSessionResponse())
-  ;
-  $async.Future<$12.GetAccountResponse> getAccount($pb.ClientContext? ctx, $12.GetAccountRequest request) =>
-    _client.invoke<$12.GetAccountResponse>(ctx, 'df', 'GetAccount', request, $12.GetAccountResponse())
-  ;
-  $async.Future<$13.ListAccountsResponse> listAccounts($pb.ClientContext? ctx, $13.ListAccountsRequest request) =>
-    _client.invoke<$13.ListAccountsResponse>(ctx, 'df', 'ListAccounts', request, $13.ListAccountsResponse())
-  ;
-  $async.Future<$14.CreateAccountResponse> createAccount($pb.ClientContext? ctx, $14.CreateAccountRequest request) =>
-    _client.invoke<$14.CreateAccountResponse>(ctx, 'df', 'CreateAccount', request, $14.CreateAccountResponse())
-  ;
-  $async.Future<$15.UpdateAccountResponse> updateAccount($pb.ClientContext? ctx, $15.UpdateAccountRequest request) =>
-    _client.invoke<$15.UpdateAccountResponse>(ctx, 'df', 'UpdateAccount', request, $15.UpdateAccountResponse())
-  ;
-  $async.Future<$16.GetAccountInfoResponse> getAccountInfo($pb.ClientContext? ctx, $16.GetAccountInfoRequest request) =>
-    _client.invoke<$16.GetAccountInfoResponse>(ctx, 'df', 'GetAccountInfo', request, $16.GetAccountInfoResponse())
-  ;
-  $async.Future<$17.ListAccountInfoResponse> listAccountInfo($pb.ClientContext? ctx, $17.ListAccountInfoRequest request) =>
-    _client.invoke<$17.ListAccountInfoResponse>(ctx, 'df', 'ListAccountInfo', request, $17.ListAccountInfoResponse())
-  ;
-  $async.Future<$18.CreateAccountInfoResponse> createAccountInfo($pb.ClientContext? ctx, $18.CreateAccountInfoRequest request) =>
-    _client.invoke<$18.CreateAccountInfoResponse>(ctx, 'df', 'CreateAccountInfo', request, $18.CreateAccountInfoResponse())
-  ;
-  $async.Future<$19.UpdateAccountInfoResponse> updateAccountInfo($pb.ClientContext? ctx, $19.UpdateAccountInfoRequest request) =>
-    _client.invoke<$19.UpdateAccountInfoResponse>(ctx, 'df', 'UpdateAccountInfo', request, $19.UpdateAccountInfoResponse())
-  ;
-  $async.Future<$20.UpdateAccountPrivacyResponse> updateAccountPrivacy($pb.ClientContext? ctx, $20.UpdateAccountPrivacyRequest request) =>
-    _client.invoke<$20.UpdateAccountPrivacyResponse>(ctx, 'df', 'UpdateAccountPrivacy', request, $20.UpdateAccountPrivacyResponse())
-  ;
-  $async.Future<$21.CreatePersonResponse> createPerson($pb.ClientContext? ctx, $21.CreatePersonRequest request) =>
-    _client.invoke<$21.CreatePersonResponse>(ctx, 'df', 'CreatePerson', request, $21.CreatePersonResponse())
-  ;
-  $async.Future<$22.UpdatePersonResponse> updatePerson($pb.ClientContext? ctx, $22.UpdatePersonRequest request) =>
-    _client.invoke<$22.UpdatePersonResponse>(ctx, 'df', 'UpdatePerson', request, $22.UpdatePersonResponse())
-  ;
-  $async.Future<$23.GetPersonResponse> getPerson($pb.ClientContext? ctx, $23.GetPersonRequest request) =>
-    _client.invoke<$23.GetPersonResponse>(ctx, 'df', 'GetPerson', request, $23.GetPersonResponse())
-  ;
-  $async.Future<$24.DeletePersonResponse> deletePerson($pb.ClientContext? ctx, $24.DeletePersonRequest request) =>
-    _client.invoke<$24.DeletePersonResponse>(ctx, 'df', 'DeletePerson', request, $24.DeletePersonResponse())
-  ;
-  $async.Future<$25.ListPersonsResponse> listPersons($pb.ClientContext? ctx, $25.ListPersonsRequest request) =>
-    _client.invoke<$25.ListPersonsResponse>(ctx, 'df', 'ListPersons', request, $25.ListPersonsResponse())
-  ;
-  $async.Future<$26.CreatePaymentResponse> createPayment($pb.ClientContext? ctx, $26.CreatePaymentRequest request) =>
-    _client.invoke<$26.CreatePaymentResponse>(ctx, 'df', 'CreatePayment', request, $26.CreatePaymentResponse())
-  ;
-  $async.Future<$27.GetPaymentResponse> getPayment($pb.ClientContext? ctx, $27.GetPaymentRequest request) =>
-    _client.invoke<$27.GetPaymentResponse>(ctx, 'df', 'GetPayment', request, $27.GetPaymentResponse())
-  ;
-  $async.Future<$28.DeletePaymentResponse> deletePayment($pb.ClientContext? ctx, $28.DeletePaymentRequest request) =>
-    _client.invoke<$28.DeletePaymentResponse>(ctx, 'df', 'DeletePayment', request, $28.DeletePaymentResponse())
-  ;
-  $async.Future<$29.ListPaymentsResponse> listPayments($pb.ClientContext? ctx, $29.ListPaymentsRequest request) =>
-    _client.invoke<$29.ListPaymentsResponse>(ctx, 'df', 'ListPayments', request, $29.ListPaymentsResponse())
-  ;
-  $async.Future<$30.UpdatePaymentResponse> updatePayment($pb.ClientContext? ctx, $30.UpdatePaymentRequest request) =>
-    _client.invoke<$30.UpdatePaymentResponse>(ctx, 'df', 'UpdatePayment', request, $30.UpdatePaymentResponse())
-  ;
-  $async.Future<$31.ListReturnsLogResponse> listReturnsLog($pb.ClientContext? ctx, $31.ListReturnsLogRequest request) =>
-    _client.invoke<$31.ListReturnsLogResponse>(ctx, 'df', 'ListReturnsLog', request, $31.ListReturnsLogResponse())
-  ;
-  $async.Future<$32.UploadDocumentResponse> uploadDocument($pb.ClientContext? ctx, $32.UploadDocumentRequest request) =>
-    _client.invoke<$32.UploadDocumentResponse>(ctx, 'df', 'UploadDocument', request, $32.UploadDocumentResponse())
-  ;
-  $async.Future<$33.DeleteDocumentResponse> deleteDocument($pb.ClientContext? ctx, $33.DeleteDocumentRequest request) =>
-    _client.invoke<$33.DeleteDocumentResponse>(ctx, 'df', 'DeleteDocument', request, $33.DeleteDocumentResponse())
-  ;
-  $async.Future<$34.VerifyEmailResponse> verifyEmail($pb.ClientContext? ctx, $34.VerifyEmailRequest request) =>
-    _client.invoke<$34.VerifyEmailResponse>(ctx, 'df', 'VerifyEmail', request, $34.VerifyEmailResponse())
-  ;
-}
-
diff --git a/frontend/app/lib/pb/service_df.pbgrpc.dart b/frontend/app/lib/pb/service_df.pbgrpc.dart
new file mode 100644
index 0000000..6a3cb48
--- /dev/null
+++ b/frontend/app/lib/pb/service_df.pbgrpc.dart
@@ -0,0 +1,605 @@
+//
+//  Generated code. Do not modify.
+//  source: service_df.proto
+//
+// @dart = 2.12
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:async' as $async;
+import 'dart:core' as $core;
+
+import 'package:grpc/service_api.dart' as $grpc;
+import 'package:protobuf/protobuf.dart' as $pb;
+
+import 'rpc_block_session.pb.dart' as $3;
+import 'rpc_create_account.pb.dart' as $6;
+import 'rpc_create_account_info.pb.dart' as $10;
+import 'rpc_create_payment.pb.dart' as $18;
+import 'rpc_create_person.pb.dart' as $13;
+import 'rpc_delete_document.pb.dart' as $25;
+import 'rpc_delete_payment.pb.dart' as $20;
+import 'rpc_delete_person.pb.dart' as $16;
+import 'rpc_get_account.pb.dart' as $4;
+import 'rpc_get_account_info.pb.dart' as $8;
+import 'rpc_get_payment.pb.dart' as $19;
+import 'rpc_get_person.pb.dart' as $15;
+import 'rpc_list_account_info.pb.dart' as $9;
+import 'rpc_list_accounts.pb.dart' as $5;
+import 'rpc_list_payments.pb.dart' as $21;
+import 'rpc_list_persons.pb.dart' as $17;
+import 'rpc_list_returns_log_by_person_id.pb.dart' as $23;
+import 'rpc_list_sessions.pb.dart' as $2;
+import 'rpc_login.pb.dart' as $0;
+import 'rpc_refresh_token.pb.dart' as $1;
+import 'rpc_update_account.pb.dart' as $7;
+import 'rpc_update_account_info.pb.dart' as $11;
+import 'rpc_update_account_privacy.pb.dart' as $12;
+import 'rpc_update_payment.pb.dart' as $22;
+import 'rpc_update_person.pb.dart' as $14;
+import 'rpc_upload_document.pb.dart' as $24;
+import 'rpc_verify_email.pb.dart' as $26;
+
+export 'service_df.pb.dart';
+
+@$pb.GrpcServiceName('pb.df')
+class dfClient extends $grpc.Client {
+  static final _$login = $grpc.ClientMethod<$0.LoginRequest, $0.LoginResponse>(
+      '/pb.df/Login',
+      ($0.LoginRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $0.LoginResponse.fromBuffer(value));
+  static final _$refreshToken = $grpc.ClientMethod<$1.RefreshTokenRequest, $1.RefreshTokenResponse>(
+      '/pb.df/RefreshToken',
+      ($1.RefreshTokenRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $1.RefreshTokenResponse.fromBuffer(value));
+  static final _$listSessions = $grpc.ClientMethod<$2.ListSessionsRequest, $2.ListSessionsResponse>(
+      '/pb.df/ListSessions',
+      ($2.ListSessionsRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $2.ListSessionsResponse.fromBuffer(value));
+  static final _$blockSession = $grpc.ClientMethod<$3.BlockSessionRequest, $3.BlockSessionResponse>(
+      '/pb.df/BlockSession',
+      ($3.BlockSessionRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $3.BlockSessionResponse.fromBuffer(value));
+  static final _$getAccount = $grpc.ClientMethod<$4.GetAccountRequest, $4.GetAccountResponse>(
+      '/pb.df/GetAccount',
+      ($4.GetAccountRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $4.GetAccountResponse.fromBuffer(value));
+  static final _$listAccounts = $grpc.ClientMethod<$5.ListAccountsRequest, $5.ListAccountsResponse>(
+      '/pb.df/ListAccounts',
+      ($5.ListAccountsRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $5.ListAccountsResponse.fromBuffer(value));
+  static final _$createAccount = $grpc.ClientMethod<$6.CreateAccountRequest, $6.CreateAccountResponse>(
+      '/pb.df/CreateAccount',
+      ($6.CreateAccountRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $6.CreateAccountResponse.fromBuffer(value));
+  static final _$updateAccount = $grpc.ClientMethod<$7.UpdateAccountRequest, $7.UpdateAccountResponse>(
+      '/pb.df/UpdateAccount',
+      ($7.UpdateAccountRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $7.UpdateAccountResponse.fromBuffer(value));
+  static final _$getAccountInfo = $grpc.ClientMethod<$8.GetAccountInfoRequest, $8.GetAccountInfoResponse>(
+      '/pb.df/GetAccountInfo',
+      ($8.GetAccountInfoRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $8.GetAccountInfoResponse.fromBuffer(value));
+  static final _$listAccountInfo = $grpc.ClientMethod<$9.ListAccountInfoRequest, $9.ListAccountInfoResponse>(
+      '/pb.df/ListAccountInfo',
+      ($9.ListAccountInfoRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $9.ListAccountInfoResponse.fromBuffer(value));
+  static final _$createAccountInfo = $grpc.ClientMethod<$10.CreateAccountInfoRequest, $10.CreateAccountInfoResponse>(
+      '/pb.df/CreateAccountInfo',
+      ($10.CreateAccountInfoRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $10.CreateAccountInfoResponse.fromBuffer(value));
+  static final _$updateAccountInfo = $grpc.ClientMethod<$11.UpdateAccountInfoRequest, $11.UpdateAccountInfoResponse>(
+      '/pb.df/UpdateAccountInfo',
+      ($11.UpdateAccountInfoRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $11.UpdateAccountInfoResponse.fromBuffer(value));
+  static final _$updateAccountPrivacy = $grpc.ClientMethod<$12.UpdateAccountPrivacyRequest, $12.UpdateAccountPrivacyResponse>(
+      '/pb.df/UpdateAccountPrivacy',
+      ($12.UpdateAccountPrivacyRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $12.UpdateAccountPrivacyResponse.fromBuffer(value));
+  static final _$createPerson = $grpc.ClientMethod<$13.CreatePersonRequest, $13.CreatePersonResponse>(
+      '/pb.df/CreatePerson',
+      ($13.CreatePersonRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $13.CreatePersonResponse.fromBuffer(value));
+  static final _$updatePerson = $grpc.ClientMethod<$14.UpdatePersonRequest, $14.UpdatePersonResponse>(
+      '/pb.df/UpdatePerson',
+      ($14.UpdatePersonRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $14.UpdatePersonResponse.fromBuffer(value));
+  static final _$getPerson = $grpc.ClientMethod<$15.GetPersonRequest, $15.GetPersonResponse>(
+      '/pb.df/GetPerson',
+      ($15.GetPersonRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $15.GetPersonResponse.fromBuffer(value));
+  static final _$deletePerson = $grpc.ClientMethod<$16.DeletePersonRequest, $16.DeletePersonResponse>(
+      '/pb.df/DeletePerson',
+      ($16.DeletePersonRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $16.DeletePersonResponse.fromBuffer(value));
+  static final _$listPersons = $grpc.ClientMethod<$17.ListPersonsRequest, $17.ListPersonsResponse>(
+      '/pb.df/ListPersons',
+      ($17.ListPersonsRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $17.ListPersonsResponse.fromBuffer(value));
+  static final _$createPayment = $grpc.ClientMethod<$18.CreatePaymentRequest, $18.CreatePaymentResponse>(
+      '/pb.df/CreatePayment',
+      ($18.CreatePaymentRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $18.CreatePaymentResponse.fromBuffer(value));
+  static final _$getPayment = $grpc.ClientMethod<$19.GetPaymentRequest, $19.GetPaymentResponse>(
+      '/pb.df/GetPayment',
+      ($19.GetPaymentRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $19.GetPaymentResponse.fromBuffer(value));
+  static final _$deletePayment = $grpc.ClientMethod<$20.DeletePaymentRequest, $20.DeletePaymentResponse>(
+      '/pb.df/DeletePayment',
+      ($20.DeletePaymentRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $20.DeletePaymentResponse.fromBuffer(value));
+  static final _$listPayments = $grpc.ClientMethod<$21.ListPaymentsRequest, $21.ListPaymentsResponse>(
+      '/pb.df/ListPayments',
+      ($21.ListPaymentsRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $21.ListPaymentsResponse.fromBuffer(value));
+  static final _$updatePayment = $grpc.ClientMethod<$22.UpdatePaymentRequest, $22.UpdatePaymentResponse>(
+      '/pb.df/UpdatePayment',
+      ($22.UpdatePaymentRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $22.UpdatePaymentResponse.fromBuffer(value));
+  static final _$listReturnsLog = $grpc.ClientMethod<$23.ListReturnsLogRequest, $23.ListReturnsLogResponse>(
+      '/pb.df/ListReturnsLog',
+      ($23.ListReturnsLogRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $23.ListReturnsLogResponse.fromBuffer(value));
+  static final _$uploadDocument = $grpc.ClientMethod<$24.UploadDocumentRequest, $24.UploadDocumentResponse>(
+      '/pb.df/UploadDocument',
+      ($24.UploadDocumentRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $24.UploadDocumentResponse.fromBuffer(value));
+  static final _$deleteDocument = $grpc.ClientMethod<$25.DeleteDocumentRequest, $25.DeleteDocumentResponse>(
+      '/pb.df/DeleteDocument',
+      ($25.DeleteDocumentRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $25.DeleteDocumentResponse.fromBuffer(value));
+  static final _$verifyEmail = $grpc.ClientMethod<$26.VerifyEmailRequest, $26.VerifyEmailResponse>(
+      '/pb.df/VerifyEmail',
+      ($26.VerifyEmailRequest value) => value.writeToBuffer(),
+      ($core.List<$core.int> value) => $26.VerifyEmailResponse.fromBuffer(value));
+
+  dfClient($grpc.ClientChannel channel,
+      {$grpc.CallOptions? options,
+      $core.Iterable<$grpc.ClientInterceptor>? interceptors})
+      : super(channel, options: options,
+        interceptors: interceptors);
+
+  $grpc.ResponseFuture<$0.LoginResponse> login($0.LoginRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$login, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$1.RefreshTokenResponse> refreshToken($1.RefreshTokenRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$refreshToken, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$2.ListSessionsResponse> listSessions($2.ListSessionsRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$listSessions, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$3.BlockSessionResponse> blockSession($3.BlockSessionRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$blockSession, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$4.GetAccountResponse> getAccount($4.GetAccountRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$getAccount, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$5.ListAccountsResponse> listAccounts($5.ListAccountsRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$listAccounts, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$6.CreateAccountResponse> createAccount($6.CreateAccountRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$createAccount, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$7.UpdateAccountResponse> updateAccount($7.UpdateAccountRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$updateAccount, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$8.GetAccountInfoResponse> getAccountInfo($8.GetAccountInfoRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$getAccountInfo, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$9.ListAccountInfoResponse> listAccountInfo($9.ListAccountInfoRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$listAccountInfo, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$10.CreateAccountInfoResponse> createAccountInfo($10.CreateAccountInfoRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$createAccountInfo, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$11.UpdateAccountInfoResponse> updateAccountInfo($11.UpdateAccountInfoRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$updateAccountInfo, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$12.UpdateAccountPrivacyResponse> updateAccountPrivacy($12.UpdateAccountPrivacyRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$updateAccountPrivacy, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$13.CreatePersonResponse> createPerson($13.CreatePersonRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$createPerson, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$14.UpdatePersonResponse> updatePerson($14.UpdatePersonRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$updatePerson, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$15.GetPersonResponse> getPerson($15.GetPersonRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$getPerson, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$16.DeletePersonResponse> deletePerson($16.DeletePersonRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$deletePerson, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$17.ListPersonsResponse> listPersons($17.ListPersonsRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$listPersons, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$18.CreatePaymentResponse> createPayment($18.CreatePaymentRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$createPayment, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$19.GetPaymentResponse> getPayment($19.GetPaymentRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$getPayment, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$20.DeletePaymentResponse> deletePayment($20.DeletePaymentRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$deletePayment, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$21.ListPaymentsResponse> listPayments($21.ListPaymentsRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$listPayments, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$22.UpdatePaymentResponse> updatePayment($22.UpdatePaymentRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$updatePayment, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$23.ListReturnsLogResponse> listReturnsLog($23.ListReturnsLogRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$listReturnsLog, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$24.UploadDocumentResponse> uploadDocument($24.UploadDocumentRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$uploadDocument, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$25.DeleteDocumentResponse> deleteDocument($25.DeleteDocumentRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$deleteDocument, request, options: options);
+  }
+
+  $grpc.ResponseFuture<$26.VerifyEmailResponse> verifyEmail($26.VerifyEmailRequest request, {$grpc.CallOptions? options}) {
+    return $createUnaryCall(_$verifyEmail, request, options: options);
+  }
+}
+
+@$pb.GrpcServiceName('pb.df')
+abstract class dfServiceBase extends $grpc.Service {
+  $core.String get $name => 'pb.df';
+
+  dfServiceBase() {
+    $addMethod($grpc.ServiceMethod<$0.LoginRequest, $0.LoginResponse>(
+        'Login',
+        login_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $0.LoginRequest.fromBuffer(value),
+        ($0.LoginResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$1.RefreshTokenRequest, $1.RefreshTokenResponse>(
+        'RefreshToken',
+        refreshToken_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $1.RefreshTokenRequest.fromBuffer(value),
+        ($1.RefreshTokenResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$2.ListSessionsRequest, $2.ListSessionsResponse>(
+        'ListSessions',
+        listSessions_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $2.ListSessionsRequest.fromBuffer(value),
+        ($2.ListSessionsResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$3.BlockSessionRequest, $3.BlockSessionResponse>(
+        'BlockSession',
+        blockSession_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $3.BlockSessionRequest.fromBuffer(value),
+        ($3.BlockSessionResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$4.GetAccountRequest, $4.GetAccountResponse>(
+        'GetAccount',
+        getAccount_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $4.GetAccountRequest.fromBuffer(value),
+        ($4.GetAccountResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$5.ListAccountsRequest, $5.ListAccountsResponse>(
+        'ListAccounts',
+        listAccounts_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $5.ListAccountsRequest.fromBuffer(value),
+        ($5.ListAccountsResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$6.CreateAccountRequest, $6.CreateAccountResponse>(
+        'CreateAccount',
+        createAccount_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $6.CreateAccountRequest.fromBuffer(value),
+        ($6.CreateAccountResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$7.UpdateAccountRequest, $7.UpdateAccountResponse>(
+        'UpdateAccount',
+        updateAccount_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $7.UpdateAccountRequest.fromBuffer(value),
+        ($7.UpdateAccountResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$8.GetAccountInfoRequest, $8.GetAccountInfoResponse>(
+        'GetAccountInfo',
+        getAccountInfo_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $8.GetAccountInfoRequest.fromBuffer(value),
+        ($8.GetAccountInfoResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$9.ListAccountInfoRequest, $9.ListAccountInfoResponse>(
+        'ListAccountInfo',
+        listAccountInfo_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $9.ListAccountInfoRequest.fromBuffer(value),
+        ($9.ListAccountInfoResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$10.CreateAccountInfoRequest, $10.CreateAccountInfoResponse>(
+        'CreateAccountInfo',
+        createAccountInfo_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $10.CreateAccountInfoRequest.fromBuffer(value),
+        ($10.CreateAccountInfoResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$11.UpdateAccountInfoRequest, $11.UpdateAccountInfoResponse>(
+        'UpdateAccountInfo',
+        updateAccountInfo_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $11.UpdateAccountInfoRequest.fromBuffer(value),
+        ($11.UpdateAccountInfoResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$12.UpdateAccountPrivacyRequest, $12.UpdateAccountPrivacyResponse>(
+        'UpdateAccountPrivacy',
+        updateAccountPrivacy_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $12.UpdateAccountPrivacyRequest.fromBuffer(value),
+        ($12.UpdateAccountPrivacyResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$13.CreatePersonRequest, $13.CreatePersonResponse>(
+        'CreatePerson',
+        createPerson_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $13.CreatePersonRequest.fromBuffer(value),
+        ($13.CreatePersonResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$14.UpdatePersonRequest, $14.UpdatePersonResponse>(
+        'UpdatePerson',
+        updatePerson_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $14.UpdatePersonRequest.fromBuffer(value),
+        ($14.UpdatePersonResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$15.GetPersonRequest, $15.GetPersonResponse>(
+        'GetPerson',
+        getPerson_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $15.GetPersonRequest.fromBuffer(value),
+        ($15.GetPersonResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$16.DeletePersonRequest, $16.DeletePersonResponse>(
+        'DeletePerson',
+        deletePerson_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $16.DeletePersonRequest.fromBuffer(value),
+        ($16.DeletePersonResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$17.ListPersonsRequest, $17.ListPersonsResponse>(
+        'ListPersons',
+        listPersons_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $17.ListPersonsRequest.fromBuffer(value),
+        ($17.ListPersonsResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$18.CreatePaymentRequest, $18.CreatePaymentResponse>(
+        'CreatePayment',
+        createPayment_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $18.CreatePaymentRequest.fromBuffer(value),
+        ($18.CreatePaymentResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$19.GetPaymentRequest, $19.GetPaymentResponse>(
+        'GetPayment',
+        getPayment_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $19.GetPaymentRequest.fromBuffer(value),
+        ($19.GetPaymentResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$20.DeletePaymentRequest, $20.DeletePaymentResponse>(
+        'DeletePayment',
+        deletePayment_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $20.DeletePaymentRequest.fromBuffer(value),
+        ($20.DeletePaymentResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$21.ListPaymentsRequest, $21.ListPaymentsResponse>(
+        'ListPayments',
+        listPayments_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $21.ListPaymentsRequest.fromBuffer(value),
+        ($21.ListPaymentsResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$22.UpdatePaymentRequest, $22.UpdatePaymentResponse>(
+        'UpdatePayment',
+        updatePayment_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $22.UpdatePaymentRequest.fromBuffer(value),
+        ($22.UpdatePaymentResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$23.ListReturnsLogRequest, $23.ListReturnsLogResponse>(
+        'ListReturnsLog',
+        listReturnsLog_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $23.ListReturnsLogRequest.fromBuffer(value),
+        ($23.ListReturnsLogResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$24.UploadDocumentRequest, $24.UploadDocumentResponse>(
+        'UploadDocument',
+        uploadDocument_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $24.UploadDocumentRequest.fromBuffer(value),
+        ($24.UploadDocumentResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$25.DeleteDocumentRequest, $25.DeleteDocumentResponse>(
+        'DeleteDocument',
+        deleteDocument_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $25.DeleteDocumentRequest.fromBuffer(value),
+        ($25.DeleteDocumentResponse value) => value.writeToBuffer()));
+    $addMethod($grpc.ServiceMethod<$26.VerifyEmailRequest, $26.VerifyEmailResponse>(
+        'VerifyEmail',
+        verifyEmail_Pre,
+        false,
+        false,
+        ($core.List<$core.int> value) => $26.VerifyEmailRequest.fromBuffer(value),
+        ($26.VerifyEmailResponse value) => value.writeToBuffer()));
+  }
+
+  $async.Future<$0.LoginResponse> login_Pre($grpc.ServiceCall call, $async.Future<$0.LoginRequest> request) async {
+    return login(call, await request);
+  }
+
+  $async.Future<$1.RefreshTokenResponse> refreshToken_Pre($grpc.ServiceCall call, $async.Future<$1.RefreshTokenRequest> request) async {
+    return refreshToken(call, await request);
+  }
+
+  $async.Future<$2.ListSessionsResponse> listSessions_Pre($grpc.ServiceCall call, $async.Future<$2.ListSessionsRequest> request) async {
+    return listSessions(call, await request);
+  }
+
+  $async.Future<$3.BlockSessionResponse> blockSession_Pre($grpc.ServiceCall call, $async.Future<$3.BlockSessionRequest> request) async {
+    return blockSession(call, await request);
+  }
+
+  $async.Future<$4.GetAccountResponse> getAccount_Pre($grpc.ServiceCall call, $async.Future<$4.GetAccountRequest> request) async {
+    return getAccount(call, await request);
+  }
+
+  $async.Future<$5.ListAccountsResponse> listAccounts_Pre($grpc.ServiceCall call, $async.Future<$5.ListAccountsRequest> request) async {
+    return listAccounts(call, await request);
+  }
+
+  $async.Future<$6.CreateAccountResponse> createAccount_Pre($grpc.ServiceCall call, $async.Future<$6.CreateAccountRequest> request) async {
+    return createAccount(call, await request);
+  }
+
+  $async.Future<$7.UpdateAccountResponse> updateAccount_Pre($grpc.ServiceCall call, $async.Future<$7.UpdateAccountRequest> request) async {
+    return updateAccount(call, await request);
+  }
+
+  $async.Future<$8.GetAccountInfoResponse> getAccountInfo_Pre($grpc.ServiceCall call, $async.Future<$8.GetAccountInfoRequest> request) async {
+    return getAccountInfo(call, await request);
+  }
+
+  $async.Future<$9.ListAccountInfoResponse> listAccountInfo_Pre($grpc.ServiceCall call, $async.Future<$9.ListAccountInfoRequest> request) async {
+    return listAccountInfo(call, await request);
+  }
+
+  $async.Future<$10.CreateAccountInfoResponse> createAccountInfo_Pre($grpc.ServiceCall call, $async.Future<$10.CreateAccountInfoRequest> request) async {
+    return createAccountInfo(call, await request);
+  }
+
+  $async.Future<$11.UpdateAccountInfoResponse> updateAccountInfo_Pre($grpc.ServiceCall call, $async.Future<$11.UpdateAccountInfoRequest> request) async {
+    return updateAccountInfo(call, await request);
+  }
+
+  $async.Future<$12.UpdateAccountPrivacyResponse> updateAccountPrivacy_Pre($grpc.ServiceCall call, $async.Future<$12.UpdateAccountPrivacyRequest> request) async {
+    return updateAccountPrivacy(call, await request);
+  }
+
+  $async.Future<$13.CreatePersonResponse> createPerson_Pre($grpc.ServiceCall call, $async.Future<$13.CreatePersonRequest> request) async {
+    return createPerson(call, await request);
+  }
+
+  $async.Future<$14.UpdatePersonResponse> updatePerson_Pre($grpc.ServiceCall call, $async.Future<$14.UpdatePersonRequest> request) async {
+    return updatePerson(call, await request);
+  }
+
+  $async.Future<$15.GetPersonResponse> getPerson_Pre($grpc.ServiceCall call, $async.Future<$15.GetPersonRequest> request) async {
+    return getPerson(call, await request);
+  }
+
+  $async.Future<$16.DeletePersonResponse> deletePerson_Pre($grpc.ServiceCall call, $async.Future<$16.DeletePersonRequest> request) async {
+    return deletePerson(call, await request);
+  }
+
+  $async.Future<$17.ListPersonsResponse> listPersons_Pre($grpc.ServiceCall call, $async.Future<$17.ListPersonsRequest> request) async {
+    return listPersons(call, await request);
+  }
+
+  $async.Future<$18.CreatePaymentResponse> createPayment_Pre($grpc.ServiceCall call, $async.Future<$18.CreatePaymentRequest> request) async {
+    return createPayment(call, await request);
+  }
+
+  $async.Future<$19.GetPaymentResponse> getPayment_Pre($grpc.ServiceCall call, $async.Future<$19.GetPaymentRequest> request) async {
+    return getPayment(call, await request);
+  }
+
+  $async.Future<$20.DeletePaymentResponse> deletePayment_Pre($grpc.ServiceCall call, $async.Future<$20.DeletePaymentRequest> request) async {
+    return deletePayment(call, await request);
+  }
+
+  $async.Future<$21.ListPaymentsResponse> listPayments_Pre($grpc.ServiceCall call, $async.Future<$21.ListPaymentsRequest> request) async {
+    return listPayments(call, await request);
+  }
+
+  $async.Future<$22.UpdatePaymentResponse> updatePayment_Pre($grpc.ServiceCall call, $async.Future<$22.UpdatePaymentRequest> request) async {
+    return updatePayment(call, await request);
+  }
+
+  $async.Future<$23.ListReturnsLogResponse> listReturnsLog_Pre($grpc.ServiceCall call, $async.Future<$23.ListReturnsLogRequest> request) async {
+    return listReturnsLog(call, await request);
+  }
+
+  $async.Future<$24.UploadDocumentResponse> uploadDocument_Pre($grpc.ServiceCall call, $async.Future<$24.UploadDocumentRequest> request) async {
+    return uploadDocument(call, await request);
+  }
+
+  $async.Future<$25.DeleteDocumentResponse> deleteDocument_Pre($grpc.ServiceCall call, $async.Future<$25.DeleteDocumentRequest> request) async {
+    return deleteDocument(call, await request);
+  }
+
+  $async.Future<$26.VerifyEmailResponse> verifyEmail_Pre($grpc.ServiceCall call, $async.Future<$26.VerifyEmailRequest> request) async {
+    return verifyEmail(call, await request);
+  }
+
+  $async.Future<$0.LoginResponse> login($grpc.ServiceCall call, $0.LoginRequest request);
+  $async.Future<$1.RefreshTokenResponse> refreshToken($grpc.ServiceCall call, $1.RefreshTokenRequest request);
+  $async.Future<$2.ListSessionsResponse> listSessions($grpc.ServiceCall call, $2.ListSessionsRequest request);
+  $async.Future<$3.BlockSessionResponse> blockSession($grpc.ServiceCall call, $3.BlockSessionRequest request);
+  $async.Future<$4.GetAccountResponse> getAccount($grpc.ServiceCall call, $4.GetAccountRequest request);
+  $async.Future<$5.ListAccountsResponse> listAccounts($grpc.ServiceCall call, $5.ListAccountsRequest request);
+  $async.Future<$6.CreateAccountResponse> createAccount($grpc.ServiceCall call, $6.CreateAccountRequest request);
+  $async.Future<$7.UpdateAccountResponse> updateAccount($grpc.ServiceCall call, $7.UpdateAccountRequest request);
+  $async.Future<$8.GetAccountInfoResponse> getAccountInfo($grpc.ServiceCall call, $8.GetAccountInfoRequest request);
+  $async.Future<$9.ListAccountInfoResponse> listAccountInfo($grpc.ServiceCall call, $9.ListAccountInfoRequest request);
+  $async.Future<$10.CreateAccountInfoResponse> createAccountInfo($grpc.ServiceCall call, $10.CreateAccountInfoRequest request);
+  $async.Future<$11.UpdateAccountInfoResponse> updateAccountInfo($grpc.ServiceCall call, $11.UpdateAccountInfoRequest request);
+  $async.Future<$12.UpdateAccountPrivacyResponse> updateAccountPrivacy($grpc.ServiceCall call, $12.UpdateAccountPrivacyRequest request);
+  $async.Future<$13.CreatePersonResponse> createPerson($grpc.ServiceCall call, $13.CreatePersonRequest request);
+  $async.Future<$14.UpdatePersonResponse> updatePerson($grpc.ServiceCall call, $14.UpdatePersonRequest request);
+  $async.Future<$15.GetPersonResponse> getPerson($grpc.ServiceCall call, $15.GetPersonRequest request);
+  $async.Future<$16.DeletePersonResponse> deletePerson($grpc.ServiceCall call, $16.DeletePersonRequest request);
+  $async.Future<$17.ListPersonsResponse> listPersons($grpc.ServiceCall call, $17.ListPersonsRequest request);
+  $async.Future<$18.CreatePaymentResponse> createPayment($grpc.ServiceCall call, $18.CreatePaymentRequest request);
+  $async.Future<$19.GetPaymentResponse> getPayment($grpc.ServiceCall call, $19.GetPaymentRequest request);
+  $async.Future<$20.DeletePaymentResponse> deletePayment($grpc.ServiceCall call, $20.DeletePaymentRequest request);
+  $async.Future<$21.ListPaymentsResponse> listPayments($grpc.ServiceCall call, $21.ListPaymentsRequest request);
+  $async.Future<$22.UpdatePaymentResponse> updatePayment($grpc.ServiceCall call, $22.UpdatePaymentRequest request);
+  $async.Future<$23.ListReturnsLogResponse> listReturnsLog($grpc.ServiceCall call, $23.ListReturnsLogRequest request);
+  $async.Future<$24.UploadDocumentResponse> uploadDocument($grpc.ServiceCall call, $24.UploadDocumentRequest request);
+  $async.Future<$25.DeleteDocumentResponse> deleteDocument($grpc.ServiceCall call, $25.DeleteDocumentRequest request);
+  $async.Future<$26.VerifyEmailResponse> verifyEmail($grpc.ServiceCall call, $26.VerifyEmailRequest request);
+}
diff --git a/frontend/app/lib/pb/service_df.pbjson.dart b/frontend/app/lib/pb/service_df.pbjson.dart
index 1ff1c56..6b26486 100644
--- a/frontend/app/lib/pb/service_df.pbjson.dart
+++ b/frontend/app/lib/pb/service_df.pbjson.dart
@@ -13,220 +13,3 @@ import 'dart:convert' as $convert;
 import 'dart:core' as $core;
 import 'dart:typed_data' as $typed_data;
 
-import 'account.pbjson.dart' as $2;
-import 'account_info.pbjson.dart' as $1;
-import 'document.pbjson.dart' as $7;
-import 'google/protobuf/timestamp.pbjson.dart' as $0;
-import 'payment.pbjson.dart' as $3;
-import 'person.pbjson.dart' as $4;
-import 'returns_log.pbjson.dart' as $5;
-import 'rpc_block_session.pbjson.dart' as $11;
-import 'rpc_create_account.pbjson.dart' as $14;
-import 'rpc_create_account_info.pbjson.dart' as $18;
-import 'rpc_create_payment.pbjson.dart' as $26;
-import 'rpc_create_person.pbjson.dart' as $21;
-import 'rpc_delete_document.pbjson.dart' as $33;
-import 'rpc_delete_payment.pbjson.dart' as $28;
-import 'rpc_delete_person.pbjson.dart' as $24;
-import 'rpc_get_account.pbjson.dart' as $12;
-import 'rpc_get_account_info.pbjson.dart' as $16;
-import 'rpc_get_payment.pbjson.dart' as $27;
-import 'rpc_get_person.pbjson.dart' as $23;
-import 'rpc_list_account_info.pbjson.dart' as $17;
-import 'rpc_list_accounts.pbjson.dart' as $13;
-import 'rpc_list_payments.pbjson.dart' as $29;
-import 'rpc_list_persons.pbjson.dart' as $25;
-import 'rpc_list_returns_log_by_person_id.pbjson.dart' as $31;
-import 'rpc_list_sessions.pbjson.dart' as $10;
-import 'rpc_login.pbjson.dart' as $8;
-import 'rpc_refresh_token.pbjson.dart' as $9;
-import 'rpc_update_account.pbjson.dart' as $15;
-import 'rpc_update_account_info.pbjson.dart' as $19;
-import 'rpc_update_account_privacy.pbjson.dart' as $20;
-import 'rpc_update_payment.pbjson.dart' as $30;
-import 'rpc_update_person.pbjson.dart' as $22;
-import 'rpc_upload_document.pbjson.dart' as $32;
-import 'rpc_verify_email.pbjson.dart' as $34;
-import 'session.pbjson.dart' as $6;
-
-const $core.Map<$core.String, $core.dynamic> dfServiceBase$json = {
-  '1': 'df',
-  '2': [
-    {'1': 'Login', '2': '.pb.LoginRequest', '3': '.pb.LoginResponse', '4': {}},
-    {'1': 'RefreshToken', '2': '.pb.RefreshTokenRequest', '3': '.pb.RefreshTokenResponse', '4': {}},
-    {'1': 'ListSessions', '2': '.pb.ListSessionsRequest', '3': '.pb.ListSessionsResponse', '4': {}},
-    {'1': 'BlockSession', '2': '.pb.BlockSessionRequest', '3': '.pb.BlockSessionResponse', '4': {}},
-    {'1': 'GetAccount', '2': '.pb.GetAccountRequest', '3': '.pb.GetAccountResponse', '4': {}},
-    {'1': 'ListAccounts', '2': '.pb.ListAccountsRequest', '3': '.pb.ListAccountsResponse', '4': {}},
-    {'1': 'CreateAccount', '2': '.pb.CreateAccountRequest', '3': '.pb.CreateAccountResponse', '4': {}},
-    {'1': 'UpdateAccount', '2': '.pb.UpdateAccountRequest', '3': '.pb.UpdateAccountResponse', '4': {}},
-    {'1': 'GetAccountInfo', '2': '.pb.GetAccountInfoRequest', '3': '.pb.GetAccountInfoResponse', '4': {}},
-    {'1': 'ListAccountInfo', '2': '.pb.ListAccountInfoRequest', '3': '.pb.ListAccountInfoResponse', '4': {}},
-    {'1': 'CreateAccountInfo', '2': '.pb.CreateAccountInfoRequest', '3': '.pb.CreateAccountInfoResponse', '4': {}},
-    {'1': 'UpdateAccountInfo', '2': '.pb.UpdateAccountInfoRequest', '3': '.pb.UpdateAccountInfoResponse', '4': {}},
-    {'1': 'UpdateAccountPrivacy', '2': '.pb.UpdateAccountPrivacyRequest', '3': '.pb.UpdateAccountPrivacyResponse', '4': {}},
-    {'1': 'CreatePerson', '2': '.pb.CreatePersonRequest', '3': '.pb.CreatePersonResponse', '4': {}},
-    {'1': 'UpdatePerson', '2': '.pb.UpdatePersonRequest', '3': '.pb.UpdatePersonResponse', '4': {}},
-    {'1': 'GetPerson', '2': '.pb.GetPersonRequest', '3': '.pb.GetPersonResponse', '4': {}},
-    {'1': 'DeletePerson', '2': '.pb.DeletePersonRequest', '3': '.pb.DeletePersonResponse', '4': {}},
-    {'1': 'ListPersons', '2': '.pb.ListPersonsRequest', '3': '.pb.ListPersonsResponse', '4': {}},
-    {'1': 'CreatePayment', '2': '.pb.CreatePaymentRequest', '3': '.pb.CreatePaymentResponse', '4': {}},
-    {'1': 'GetPayment', '2': '.pb.GetPaymentRequest', '3': '.pb.GetPaymentResponse', '4': {}},
-    {'1': 'DeletePayment', '2': '.pb.DeletePaymentRequest', '3': '.pb.DeletePaymentResponse', '4': {}},
-    {'1': 'ListPayments', '2': '.pb.ListPaymentsRequest', '3': '.pb.ListPaymentsResponse', '4': {}},
-    {'1': 'UpdatePayment', '2': '.pb.UpdatePaymentRequest', '3': '.pb.UpdatePaymentResponse', '4': {}},
-    {'1': 'ListReturnsLog', '2': '.pb.ListReturnsLogRequest', '3': '.pb.ListReturnsLogResponse', '4': {}},
-    {'1': 'UploadDocument', '2': '.pb.UploadDocumentRequest', '3': '.pb.UploadDocumentResponse', '4': {}},
-    {'1': 'DeleteDocument', '2': '.pb.DeleteDocumentRequest', '3': '.pb.DeleteDocumentResponse', '4': {}},
-    {'1': 'VerifyEmail', '2': '.pb.VerifyEmailRequest', '3': '.pb.VerifyEmailResponse', '4': {}},
-  ],
-  '3': {},
-};
-
-@$core.Deprecated('Use dfServiceDescriptor instead')
-const $core.Map<$core.String, $core.Map<$core.String, $core.dynamic>> dfServiceBase$messageJson = {
-  '.pb.LoginRequest': $8.LoginRequest$json,
-  '.pb.LoginResponse': $8.LoginResponse$json,
-  '.google.protobuf.Timestamp': $0.Timestamp$json,
-  '.pb.RefreshTokenRequest': $9.RefreshTokenRequest$json,
-  '.pb.RefreshTokenResponse': $9.RefreshTokenResponse$json,
-  '.pb.ListSessionsRequest': $10.ListSessionsRequest$json,
-  '.pb.ListSessionsResponse': $10.ListSessionsResponse$json,
-  '.pb.Session': $6.Session$json,
-  '.pb.BlockSessionRequest': $11.BlockSessionRequest$json,
-  '.pb.BlockSessionResponse': $11.BlockSessionResponse$json,
-  '.pb.GetAccountRequest': $12.GetAccountRequest$json,
-  '.pb.GetAccountResponse': $12.GetAccountResponse$json,
-  '.pb.Account': $2.Account$json,
-  '.pb.ListAccountsRequest': $13.ListAccountsRequest$json,
-  '.pb.ListAccountsResponse': $13.ListAccountsResponse$json,
-  '.pb.CreateAccountRequest': $14.CreateAccountRequest$json,
-  '.pb.CreateAccountResponse': $14.CreateAccountResponse$json,
-  '.pb.UpdateAccountRequest': $15.UpdateAccountRequest$json,
-  '.pb.UpdateAccountResponse': $15.UpdateAccountResponse$json,
-  '.pb.GetAccountInfoRequest': $16.GetAccountInfoRequest$json,
-  '.pb.GetAccountInfoResponse': $16.GetAccountInfoResponse$json,
-  '.pb.AccountInfo': $1.AccountInfo$json,
-  '.pb.ListAccountInfoRequest': $17.ListAccountInfoRequest$json,
-  '.pb.ListAccountInfoResponse': $17.ListAccountInfoResponse$json,
-  '.pb.CreateAccountInfoRequest': $18.CreateAccountInfoRequest$json,
-  '.pb.CreateAccountInfoResponse': $18.CreateAccountInfoResponse$json,
-  '.pb.UpdateAccountInfoRequest': $19.UpdateAccountInfoRequest$json,
-  '.pb.UpdateAccountInfoResponse': $19.UpdateAccountInfoResponse$json,
-  '.pb.UpdateAccountPrivacyRequest': $20.UpdateAccountPrivacyRequest$json,
-  '.pb.UpdateAccountPrivacyResponse': $20.UpdateAccountPrivacyResponse$json,
-  '.pb.CreatePersonRequest': $21.CreatePersonRequest$json,
-  '.pb.CreatePersonResponse': $21.CreatePersonResponse$json,
-  '.pb.Person': $4.Person$json,
-  '.pb.UpdatePersonRequest': $22.UpdatePersonRequest$json,
-  '.pb.UpdatePersonResponse': $22.UpdatePersonResponse$json,
-  '.pb.GetPersonRequest': $23.GetPersonRequest$json,
-  '.pb.GetPersonResponse': $23.GetPersonResponse$json,
-  '.pb.DeletePersonRequest': $24.DeletePersonRequest$json,
-  '.pb.DeletePersonResponse': $24.DeletePersonResponse$json,
-  '.pb.ListPersonsRequest': $25.ListPersonsRequest$json,
-  '.pb.ListPersonsResponse': $25.ListPersonsResponse$json,
-  '.pb.CreatePaymentRequest': $26.CreatePaymentRequest$json,
-  '.pb.CreatePaymentResponse': $26.CreatePaymentResponse$json,
-  '.pb.Payment': $3.Payment$json,
-  '.pb.GetPaymentRequest': $27.GetPaymentRequest$json,
-  '.pb.GetPaymentResponse': $27.GetPaymentResponse$json,
-  '.pb.DeletePaymentRequest': $28.DeletePaymentRequest$json,
-  '.pb.DeletePaymentResponse': $28.DeletePaymentResponse$json,
-  '.pb.ListPaymentsRequest': $29.ListPaymentsRequest$json,
-  '.pb.ListPaymentsResponse': $29.ListPaymentsResponse$json,
-  '.pb.UpdatePaymentRequest': $30.UpdatePaymentRequest$json,
-  '.pb.UpdatePaymentResponse': $30.UpdatePaymentResponse$json,
-  '.pb.ListReturnsLogRequest': $31.ListReturnsLogRequest$json,
-  '.pb.ListReturnsLogResponse': $31.ListReturnsLogResponse$json,
-  '.pb.ReturnsLog': $5.ReturnsLog$json,
-  '.pb.UploadDocumentRequest': $32.UploadDocumentRequest$json,
-  '.pb.UploadDocumentResponse': $32.UploadDocumentResponse$json,
-  '.pb.Document': $7.Document$json,
-  '.pb.DeleteDocumentRequest': $33.DeleteDocumentRequest$json,
-  '.pb.DeleteDocumentResponse': $33.DeleteDocumentResponse$json,
-  '.pb.VerifyEmailRequest': $34.VerifyEmailRequest$json,
-  '.pb.VerifyEmailResponse': $34.VerifyEmailResponse$json,
-};
-
-/// Descriptor for `df`. Decode as a `google.protobuf.ServiceDescriptorProto`.
-final $typed_data.Uint8List dfServiceDescriptor = $convert.base64Decode(
-    'CgJkZhJCCgVMb2dpbhIQLnBiLkxvZ2luUmVxdWVzdBoRLnBiLkxvZ2luUmVzcG9uc2UiFILT5J'
-    'MCDiIJL3YxL2xvZ2luOgEqEmgKDFJlZnJlc2hUb2tlbhIXLnBiLlJlZnJlc2hUb2tlblJlcXVl'
-    'c3QaGC5wYi5SZWZyZXNoVG9rZW5SZXNwb25zZSIlgtPkkwIfIhovdjEvc2Vzc2lvbnMvcmVmcm'
-    'VzaF90b2tlbjoBKhKkAQoMTGlzdFNlc3Npb25zEhcucGIuTGlzdFNlc3Npb25zUmVxdWVzdBoY'
-    'LnBiLkxpc3RTZXNzaW9uc1Jlc3BvbnNlImGSQS8SG0xpc3QgU2Vzc2lvbnMgYnkgYWNjb3VudF'
-    '9pZGIQCg4KCkJlYXJlckF1dGgSAILT5JMCKRInL3YxL3Nlc3Npb25zL2xpc3Rfc2Vzc2lvbnMv'
-    'e2FjY291bnRfaWR9EpIBCgxCbG9ja1Nlc3Npb24SFy5wYi5CbG9ja1Nlc3Npb25SZXF1ZXN0Gh'
-    'gucGIuQmxvY2tTZXNzaW9uUmVzcG9uc2UiT5JBJxITQmxvY2sgU2Vzc2lvbiBieSBJRGIQCg4K'
-    'CkJlYXJlckF1dGgSAILT5JMCHzIaL3YxL3Nlc3Npb25zL2Jsb2NrX3Nlc3Npb246ASoSkgEKCk'
-    'dldEFjY291bnQSFS5wYi5HZXRBY2NvdW50UmVxdWVzdBoWLnBiLkdldEFjY291bnRSZXNwb25z'
-    'ZSJVkkEtEhlHZXQgQWNjb3VudCBieSBhY2NvdW50X2lkYhAKDgoKQmVhcmVyQXV0aBIAgtPkkw'
-    'IfEh0vdjEvYWNjb3VudHMvZ2V0X2FjY291bnQve2lkfRKWAQoMTGlzdEFjY291bnRzEhcucGIu'
-    'TGlzdEFjY291bnRzUmVxdWVzdBoYLnBiLkxpc3RBY2NvdW50c1Jlc3BvbnNlIlOSQS4SGkxpc3'
-    'QgQWNjb3VudHMgW2FkbWluIG9ubHldYhAKDgoKQmVhcmVyQXV0aBIAgtPkkwIcEhovdjEvYWNj'
-    'b3VudHMvbGlzdF9hY2NvdW50cxKDAQoNQ3JlYXRlQWNjb3VudBIYLnBiLkNyZWF0ZUFjY291bn'
-    'RSZXF1ZXN0GhkucGIuQ3JlYXRlQWNjb3VudFJlc3BvbnNlIj2SQRQSEkNyZWF0ZSBBY2NvdW50'
-    'SW5mb4LT5JMCICIbL3YxL2FjY291bnRzL2NyZWF0ZV9hY2NvdW50OgEqEpEBCg1VcGRhdGVBY2'
-    'NvdW50EhgucGIuVXBkYXRlQWNjb3VudFJlcXVlc3QaGS5wYi5VcGRhdGVBY2NvdW50UmVzcG9u'
-    'c2UiS5JBIhIOVXBkYXRlIEFjY291bnRiEAoOCgpCZWFyZXJBdXRoEgCC0+STAiAyGy92MS9hY2'
-    'NvdW50cy91cGRhdGVfYWNjb3VudDoBKhKvAQoOR2V0QWNjb3VudEluZm8SGS5wYi5HZXRBY2Nv'
-    'dW50SW5mb1JlcXVlc3QaGi5wYi5HZXRBY2NvdW50SW5mb1Jlc3BvbnNlImaSQTESHUdldCBBY2'
-    'NvdW50SW5mbyBieSBhY2NvdW50X2lkYhAKDgoKQmVhcmVyQXV0aBIAgtPkkwIsEiovdjEvYWNj'
-    'b3VudHMvZ2V0X2FjY291bnRfaW5mby97YWNjb3VudF9pZH0SpwEKD0xpc3RBY2NvdW50SW5mbx'
-    'IaLnBiLkxpc3RBY2NvdW50SW5mb1JlcXVlc3QaGy5wYi5MaXN0QWNjb3VudEluZm9SZXNwb25z'
-    'ZSJbkkEyEh5MaXN0IEFjY291bnRJbmZvcyBbYWRtaW4gb25seV1iEAoOCgpCZWFyZXJBdXRoEg'
-    'CC0+STAiASHi92MS9hY2NvdW50cy9saXN0X2FjY291bnRfaW5mbxKmAQoRQ3JlYXRlQWNjb3Vu'
-    'dEluZm8SHC5wYi5DcmVhdGVBY2NvdW50SW5mb1JlcXVlc3QaHS5wYi5DcmVhdGVBY2NvdW50SW'
-    '5mb1Jlc3BvbnNlIlSSQSYSEkNyZWF0ZSBBY2NvdW50SW5mb2IQCg4KCkJlYXJlckF1dGgSAILT'
-    '5JMCJSIgL3YxL2FjY291bnRzL2NyZWF0ZV9hY2NvdW50X2luZm86ASoSpgEKEVVwZGF0ZUFjY2'
-    '91bnRJbmZvEhwucGIuVXBkYXRlQWNjb3VudEluZm9SZXF1ZXN0Gh0ucGIuVXBkYXRlQWNjb3Vu'
-    'dEluZm9SZXNwb25zZSJUkkEmEhJVcGRhdGUgQWNjb3VudEluZm9iEAoOCgpCZWFyZXJBdXRoEg'
-    'CC0+STAiUyIC92MS9hY2NvdW50cy91cGRhdGVfYWNjb3VudF9pbmZvOgEqEr8BChRVcGRhdGVB'
-    'Y2NvdW50UHJpdmFjeRIfLnBiLlVwZGF0ZUFjY291bnRQcml2YWN5UmVxdWVzdBogLnBiLlVwZG'
-    'F0ZUFjY291bnRQcml2YWN5UmVzcG9uc2UiZJJBMxIfVXBkYXRlIEFjY291bnQgUHJpdmFjeSBT'
-    'ZXR0aW5nc2IQCg4KCkJlYXJlckF1dGgSAILT5JMCKDIjL3YxL2FjY291bnRzL3VwZGF0ZV9hY2'
-    'NvdW50X3ByaXZhY3k6ASoSiwEKDENyZWF0ZVBlcnNvbhIXLnBiLkNyZWF0ZVBlcnNvblJlcXVl'
-    'c3QaGC5wYi5DcmVhdGVQZXJzb25SZXNwb25zZSJIkkEhEg1DcmVhdGUgUGVyc29uYhAKDgoKQm'
-    'VhcmVyQXV0aBIAgtPkkwIeIhkvdjEvcGVyc29ucy9jcmVhdGVfcGVyc29uOgEqEosBCgxVcGRh'
-    'dGVQZXJzb24SFy5wYi5VcGRhdGVQZXJzb25SZXF1ZXN0GhgucGIuVXBkYXRlUGVyc29uUmVzcG'
-    '9uc2UiSJJBIRINVXBkYXRlIFBlcnNvbmIQCg4KCkJlYXJlckF1dGgSAILT5JMCHjIZL3YxL3Bl'
-    'cnNvbnMvdXBkYXRlX3BlcnNvbjoBKhKEAQoJR2V0UGVyc29uEhQucGIuR2V0UGVyc29uUmVxdW'
-    'VzdBoVLnBiLkdldFBlcnNvblJlc3BvbnNlIkqSQSQSEEdldCBQZXJzb24gYnkgSURiEAoOCgpC'
-    'ZWFyZXJBdXRoEgCC0+STAh0SGy92MS9wZXJzb25zL2dldF9wZXJzb24ve2lkfRKTAQoMRGVsZX'
-    'RlUGVyc29uEhcucGIuRGVsZXRlUGVyc29uUmVxdWVzdBoYLnBiLkRlbGV0ZVBlcnNvblJlc3Bv'
-    'bnNlIlCSQScSE0RlbGV0ZSBQZXJzb24gYnkgSURiEAoOCgpCZWFyZXJBdXRoEgCC0+STAiAqHi'
-    '92MS9wZXJzb25zL2RlbGV0ZV9wZXJzb24ve2lkfRKeAQoLTGlzdFBlcnNvbnMSFi5wYi5MaXN0'
-    'UGVyc29uc1JlcXVlc3QaFy5wYi5MaXN0UGVyc29uc1Jlc3BvbnNlIl6SQS4SGkxpc3QgUGVyc2'
-    '9ucyBieSBhY2NvdW50X2lkYhAKDgoKQmVhcmVyQXV0aBIAgtPkkwInEiUvdjEvcGVyc29ucy9s'
-    'aXN0X3BlcnNvbnMve2FjY291bnRfaWR9EpEBCg1DcmVhdGVQYXltZW50EhgucGIuQ3JlYXRlUG'
-    'F5bWVudFJlcXVlc3QaGS5wYi5DcmVhdGVQYXltZW50UmVzcG9uc2UiS5JBIhIOQ3JlYXRlIFBh'
-    'eW1lbnRiEAoOCgpCZWFyZXJBdXRoEgCC0+STAiAiGy92MS9wYXltZW50cy9jcmVhdGVfcGF5bW'
-    'VudDoBKhKKAQoKR2V0UGF5bWVudBIVLnBiLkdldFBheW1lbnRSZXF1ZXN0GhYucGIuR2V0UGF5'
-    'bWVudFJlc3BvbnNlIk2SQSUSEUdldCBQYXltZW50IGJ5IElEYhAKDgoKQmVhcmVyQXV0aBIAgt'
-    'PkkwIfEh0vdjEvcGF5bWVudHMvZ2V0X3BheW1lbnQve2lkfRKZAQoNRGVsZXRlUGF5bWVudBIY'
-    'LnBiLkRlbGV0ZVBheW1lbnRSZXF1ZXN0GhkucGIuRGVsZXRlUGF5bWVudFJlc3BvbnNlIlOSQS'
-    'gSFERlbGV0ZSBQYXltZW50IGJ5IElEYhAKDgoKQmVhcmVyQXV0aBIAgtPkkwIiKiAvdjEvcGF5'
-    'bWVudHMvZGVsZXRlX3BheW1lbnQve2lkfRKkAQoMTGlzdFBheW1lbnRzEhcucGIuTGlzdFBheW'
-    '1lbnRzUmVxdWVzdBoYLnBiLkxpc3RQYXltZW50c1Jlc3BvbnNlImGSQS8SG0xpc3QgUGF5bWVu'
-    'dHMgYnkgYWNjb3VudF9pZGIQCg4KCkJlYXJlckF1dGgSAILT5JMCKRInL3YxL3BheW1lbnRzL2'
-    'xpc3RfcGF5bWVudHMve2FjY291bnRfaWR9EpEBCg1VcGRhdGVQYXltZW50EhgucGIuVXBkYXRl'
-    'UGF5bWVudFJlcXVlc3QaGS5wYi5VcGRhdGVQYXltZW50UmVzcG9uc2UiS5JBIhIOVXBkYXRlIF'
-    'BheW1lbnRiEAoOCgpCZWFyZXJBdXRoEgCC0+STAiAyGy92MS9wYXltZW50cy91cGRhdGVfcGF5'
-    'bWVudDoBKhKwAQoOTGlzdFJldHVybnNMb2cSGS5wYi5MaXN0UmV0dXJuc0xvZ1JlcXVlc3QaGi'
-    '5wYi5MaXN0UmV0dXJuc0xvZ1Jlc3BvbnNlImeSQTASHExpc3QgUmV0dXJuc0xvZyBieSBwZXJz'
-    'b25faWRiEAoOCgpCZWFyZXJBdXRoEgCC0+STAi4SLC92MS9yZXR1cm5zX2xvZy9saXN0X3JldH'
-    'VybnNfbG9nL3twZXJzb25faWR9EsoCCg5VcGxvYWREb2N1bWVudBIZLnBiLlVwbG9hZERvY3Vt'
-    'ZW50UmVxdWVzdBoaLnBiLlVwbG9hZERvY3VtZW50UmVzcG9uc2UigAKSQeABEhtVcGxvYWQgRG'
-    '9jdW1lbnQgW29ubHkgSFRUUF0argFUZXN0aW5nIHZpYSBzd2FnZ2VyIGlzIG5vdCBwb3NzaWJs'
-    'ZS4gVHJ5IGBgYGN1cmwgLVggUE9TVCAtSCAiQXV0aG9yaXphdGlvbjogQmVhcmVyIHt0b2tlbn'
-    '0iIC1GICJmaWxlPUAvcGF0aC90by9maWxlIiAtRiAicGVyc29uX2lkPTEiICJodHRwOi8ve3Nl'
-    'cnZlclVSSX0vZG9jdW1lbnRzL3VwbG9hZCJgYGBiEAoOCgpCZWFyZXJBdXRoEgCC0+STAhYiES'
-    '9kb2N1bWVudHMvdXBsb2FkOgEqEp8BCg5EZWxldGVEb2N1bWVudBIZLnBiLkRlbGV0ZURvY3Vt'
-    'ZW50UmVxdWVzdBoaLnBiLkRlbGV0ZURvY3VtZW50UmVzcG9uc2UiVpJBKRIVRGVsZXRlIERvY3'
-    'VtZW50IGJ5IElEYhAKDgoKQmVhcmVyQXV0aBIAgtPkkwIkKiIvdjEvZG9jdW1lbnRzL2RlbGV0'
-    'ZV9kb2N1bWVudC97aWR9EqIBCgtWZXJpZnlFbWFpbBIWLnBiLlZlcmlmeUVtYWlsUmVxdWVzdB'
-    'oXLnBiLlZlcmlmeUVtYWlsUmVzcG9uc2UiYpJBLRIrVmVyaWZ5IEVtYWlsIHdpdGggYWNjb3Vu'
-    'dF9pZCBhbmQgc2VjcmV0X2tleYLT5JMCLBIqL3YxL3ZlcmlmeV9lbWFpbC97YWNjb3VudF9pZH'
-    '0ve3NlY3JldF9rZXl9GgeSQQQSAmRm');
-
diff --git a/frontend/app/lib/pb/service_df.pbserver.dart b/frontend/app/lib/pb/service_df.pbserver.dart
deleted file mode 100644
index 6ed842d..0000000
--- a/frontend/app/lib/pb/service_df.pbserver.dart
+++ /dev/null
@@ -1,147 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: service_df.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-import 'dart:async' as $async;
-import 'dart:core' as $core;
-
-import 'package:protobuf/protobuf.dart' as $pb;
-
-import 'rpc_block_session.pb.dart' as $11;
-import 'rpc_create_account.pb.dart' as $14;
-import 'rpc_create_account_info.pb.dart' as $18;
-import 'rpc_create_payment.pb.dart' as $26;
-import 'rpc_create_person.pb.dart' as $21;
-import 'rpc_delete_document.pb.dart' as $33;
-import 'rpc_delete_payment.pb.dart' as $28;
-import 'rpc_delete_person.pb.dart' as $24;
-import 'rpc_get_account.pb.dart' as $12;
-import 'rpc_get_account_info.pb.dart' as $16;
-import 'rpc_get_payment.pb.dart' as $27;
-import 'rpc_get_person.pb.dart' as $23;
-import 'rpc_list_account_info.pb.dart' as $17;
-import 'rpc_list_accounts.pb.dart' as $13;
-import 'rpc_list_payments.pb.dart' as $29;
-import 'rpc_list_persons.pb.dart' as $25;
-import 'rpc_list_returns_log_by_person_id.pb.dart' as $31;
-import 'rpc_list_sessions.pb.dart' as $10;
-import 'rpc_login.pb.dart' as $8;
-import 'rpc_refresh_token.pb.dart' as $9;
-import 'rpc_update_account.pb.dart' as $15;
-import 'rpc_update_account_info.pb.dart' as $19;
-import 'rpc_update_account_privacy.pb.dart' as $20;
-import 'rpc_update_payment.pb.dart' as $30;
-import 'rpc_update_person.pb.dart' as $22;
-import 'rpc_upload_document.pb.dart' as $32;
-import 'rpc_verify_email.pb.dart' as $34;
-import 'service_df.pbjson.dart';
-
-export 'service_df.pb.dart';
-
-abstract class dfServiceBase extends $pb.GeneratedService {
-  $async.Future<$8.LoginResponse> login($pb.ServerContext ctx, $8.LoginRequest request);
-  $async.Future<$9.RefreshTokenResponse> refreshToken($pb.ServerContext ctx, $9.RefreshTokenRequest request);
-  $async.Future<$10.ListSessionsResponse> listSessions($pb.ServerContext ctx, $10.ListSessionsRequest request);
-  $async.Future<$11.BlockSessionResponse> blockSession($pb.ServerContext ctx, $11.BlockSessionRequest request);
-  $async.Future<$12.GetAccountResponse> getAccount($pb.ServerContext ctx, $12.GetAccountRequest request);
-  $async.Future<$13.ListAccountsResponse> listAccounts($pb.ServerContext ctx, $13.ListAccountsRequest request);
-  $async.Future<$14.CreateAccountResponse> createAccount($pb.ServerContext ctx, $14.CreateAccountRequest request);
-  $async.Future<$15.UpdateAccountResponse> updateAccount($pb.ServerContext ctx, $15.UpdateAccountRequest request);
-  $async.Future<$16.GetAccountInfoResponse> getAccountInfo($pb.ServerContext ctx, $16.GetAccountInfoRequest request);
-  $async.Future<$17.ListAccountInfoResponse> listAccountInfo($pb.ServerContext ctx, $17.ListAccountInfoRequest request);
-  $async.Future<$18.CreateAccountInfoResponse> createAccountInfo($pb.ServerContext ctx, $18.CreateAccountInfoRequest request);
-  $async.Future<$19.UpdateAccountInfoResponse> updateAccountInfo($pb.ServerContext ctx, $19.UpdateAccountInfoRequest request);
-  $async.Future<$20.UpdateAccountPrivacyResponse> updateAccountPrivacy($pb.ServerContext ctx, $20.UpdateAccountPrivacyRequest request);
-  $async.Future<$21.CreatePersonResponse> createPerson($pb.ServerContext ctx, $21.CreatePersonRequest request);
-  $async.Future<$22.UpdatePersonResponse> updatePerson($pb.ServerContext ctx, $22.UpdatePersonRequest request);
-  $async.Future<$23.GetPersonResponse> getPerson($pb.ServerContext ctx, $23.GetPersonRequest request);
-  $async.Future<$24.DeletePersonResponse> deletePerson($pb.ServerContext ctx, $24.DeletePersonRequest request);
-  $async.Future<$25.ListPersonsResponse> listPersons($pb.ServerContext ctx, $25.ListPersonsRequest request);
-  $async.Future<$26.CreatePaymentResponse> createPayment($pb.ServerContext ctx, $26.CreatePaymentRequest request);
-  $async.Future<$27.GetPaymentResponse> getPayment($pb.ServerContext ctx, $27.GetPaymentRequest request);
-  $async.Future<$28.DeletePaymentResponse> deletePayment($pb.ServerContext ctx, $28.DeletePaymentRequest request);
-  $async.Future<$29.ListPaymentsResponse> listPayments($pb.ServerContext ctx, $29.ListPaymentsRequest request);
-  $async.Future<$30.UpdatePaymentResponse> updatePayment($pb.ServerContext ctx, $30.UpdatePaymentRequest request);
-  $async.Future<$31.ListReturnsLogResponse> listReturnsLog($pb.ServerContext ctx, $31.ListReturnsLogRequest request);
-  $async.Future<$32.UploadDocumentResponse> uploadDocument($pb.ServerContext ctx, $32.UploadDocumentRequest request);
-  $async.Future<$33.DeleteDocumentResponse> deleteDocument($pb.ServerContext ctx, $33.DeleteDocumentRequest request);
-  $async.Future<$34.VerifyEmailResponse> verifyEmail($pb.ServerContext ctx, $34.VerifyEmailRequest request);
-
-  $pb.GeneratedMessage createRequest($core.String methodName) {
-    switch (methodName) {
-      case 'Login': return $8.LoginRequest();
-      case 'RefreshToken': return $9.RefreshTokenRequest();
-      case 'ListSessions': return $10.ListSessionsRequest();
-      case 'BlockSession': return $11.BlockSessionRequest();
-      case 'GetAccount': return $12.GetAccountRequest();
-      case 'ListAccounts': return $13.ListAccountsRequest();
-      case 'CreateAccount': return $14.CreateAccountRequest();
-      case 'UpdateAccount': return $15.UpdateAccountRequest();
-      case 'GetAccountInfo': return $16.GetAccountInfoRequest();
-      case 'ListAccountInfo': return $17.ListAccountInfoRequest();
-      case 'CreateAccountInfo': return $18.CreateAccountInfoRequest();
-      case 'UpdateAccountInfo': return $19.UpdateAccountInfoRequest();
-      case 'UpdateAccountPrivacy': return $20.UpdateAccountPrivacyRequest();
-      case 'CreatePerson': return $21.CreatePersonRequest();
-      case 'UpdatePerson': return $22.UpdatePersonRequest();
-      case 'GetPerson': return $23.GetPersonRequest();
-      case 'DeletePerson': return $24.DeletePersonRequest();
-      case 'ListPersons': return $25.ListPersonsRequest();
-      case 'CreatePayment': return $26.CreatePaymentRequest();
-      case 'GetPayment': return $27.GetPaymentRequest();
-      case 'DeletePayment': return $28.DeletePaymentRequest();
-      case 'ListPayments': return $29.ListPaymentsRequest();
-      case 'UpdatePayment': return $30.UpdatePaymentRequest();
-      case 'ListReturnsLog': return $31.ListReturnsLogRequest();
-      case 'UploadDocument': return $32.UploadDocumentRequest();
-      case 'DeleteDocument': return $33.DeleteDocumentRequest();
-      case 'VerifyEmail': return $34.VerifyEmailRequest();
-      default: throw $core.ArgumentError('Unknown method: $methodName');
-    }
-  }
-
-  $async.Future<$pb.GeneratedMessage> handleCall($pb.ServerContext ctx, $core.String methodName, $pb.GeneratedMessage request) {
-    switch (methodName) {
-      case 'Login': return this.login(ctx, request as $8.LoginRequest);
-      case 'RefreshToken': return this.refreshToken(ctx, request as $9.RefreshTokenRequest);
-      case 'ListSessions': return this.listSessions(ctx, request as $10.ListSessionsRequest);
-      case 'BlockSession': return this.blockSession(ctx, request as $11.BlockSessionRequest);
-      case 'GetAccount': return this.getAccount(ctx, request as $12.GetAccountRequest);
-      case 'ListAccounts': return this.listAccounts(ctx, request as $13.ListAccountsRequest);
-      case 'CreateAccount': return this.createAccount(ctx, request as $14.CreateAccountRequest);
-      case 'UpdateAccount': return this.updateAccount(ctx, request as $15.UpdateAccountRequest);
-      case 'GetAccountInfo': return this.getAccountInfo(ctx, request as $16.GetAccountInfoRequest);
-      case 'ListAccountInfo': return this.listAccountInfo(ctx, request as $17.ListAccountInfoRequest);
-      case 'CreateAccountInfo': return this.createAccountInfo(ctx, request as $18.CreateAccountInfoRequest);
-      case 'UpdateAccountInfo': return this.updateAccountInfo(ctx, request as $19.UpdateAccountInfoRequest);
-      case 'UpdateAccountPrivacy': return this.updateAccountPrivacy(ctx, request as $20.UpdateAccountPrivacyRequest);
-      case 'CreatePerson': return this.createPerson(ctx, request as $21.CreatePersonRequest);
-      case 'UpdatePerson': return this.updatePerson(ctx, request as $22.UpdatePersonRequest);
-      case 'GetPerson': return this.getPerson(ctx, request as $23.GetPersonRequest);
-      case 'DeletePerson': return this.deletePerson(ctx, request as $24.DeletePersonRequest);
-      case 'ListPersons': return this.listPersons(ctx, request as $25.ListPersonsRequest);
-      case 'CreatePayment': return this.createPayment(ctx, request as $26.CreatePaymentRequest);
-      case 'GetPayment': return this.getPayment(ctx, request as $27.GetPaymentRequest);
-      case 'DeletePayment': return this.deletePayment(ctx, request as $28.DeletePaymentRequest);
-      case 'ListPayments': return this.listPayments(ctx, request as $29.ListPaymentsRequest);
-      case 'UpdatePayment': return this.updatePayment(ctx, request as $30.UpdatePaymentRequest);
-      case 'ListReturnsLog': return this.listReturnsLog(ctx, request as $31.ListReturnsLogRequest);
-      case 'UploadDocument': return this.uploadDocument(ctx, request as $32.UploadDocumentRequest);
-      case 'DeleteDocument': return this.deleteDocument(ctx, request as $33.DeleteDocumentRequest);
-      case 'VerifyEmail': return this.verifyEmail(ctx, request as $34.VerifyEmailRequest);
-      default: throw $core.ArgumentError('Unknown method: $methodName');
-    }
-  }
-
-  $core.Map<$core.String, $core.dynamic> get $json => dfServiceBase$json;
-  $core.Map<$core.String, $core.Map<$core.String, $core.dynamic>> get $messageJson => dfServiceBase$messageJson;
-}
-
diff --git a/frontend/app/lib/pb/session.pb.dart b/frontend/app/lib/pb/session.pb.dart
index d41a3ba..60af26d 100644
--- a/frontend/app/lib/pb/session.pb.dart
+++ b/frontend/app/lib/pb/session.pb.dart
@@ -14,7 +14,7 @@ import 'dart:core' as $core;
 import 'package:fixnum/fixnum.dart' as $fixnum;
 import 'package:protobuf/protobuf.dart' as $pb;
 
-import 'google/protobuf/timestamp.pb.dart' as $0;
+import 'google/protobuf/timestamp.pb.dart' as $27;
 
 class Session extends $pb.GeneratedMessage {
   factory Session({
@@ -23,9 +23,9 @@ class Session extends $pb.GeneratedMessage {
     $core.String? userAgent,
     $core.String? clientIp,
     $core.bool? isBlocked,
-    $0.Timestamp? expiresAt,
+    $27.Timestamp? expiresAt,
     $core.String? refreshToken,
-    $0.Timestamp? createdAt,
+    $27.Timestamp? createdAt,
   }) {
     final $result = create();
     if (id != null) {
@@ -64,9 +64,9 @@ class Session extends $pb.GeneratedMessage {
     ..aOS(3, _omitFieldNames ? '' : 'userAgent')
     ..aOS(4, _omitFieldNames ? '' : 'clientIp')
     ..aOB(5, _omitFieldNames ? '' : 'isBlocked')
-    ..aOM<$0.Timestamp>(6, _omitFieldNames ? '' : 'expiresAt', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(6, _omitFieldNames ? '' : 'expiresAt', subBuilder: $27.Timestamp.create)
     ..aOS(7, _omitFieldNames ? '' : 'refreshToken')
-    ..aOM<$0.Timestamp>(8, _omitFieldNames ? '' : 'createdAt', subBuilder: $0.Timestamp.create)
+    ..aOM<$27.Timestamp>(8, _omitFieldNames ? '' : 'createdAt', subBuilder: $27.Timestamp.create)
     ..hasRequiredFields = false
   ;
 
@@ -137,15 +137,15 @@ class Session extends $pb.GeneratedMessage {
   void clearIsBlocked() => clearField(5);
 
   @$pb.TagNumber(6)
-  $0.Timestamp get expiresAt => $_getN(5);
+  $27.Timestamp get expiresAt => $_getN(5);
   @$pb.TagNumber(6)
-  set expiresAt($0.Timestamp v) { setField(6, v); }
+  set expiresAt($27.Timestamp v) { setField(6, v); }
   @$pb.TagNumber(6)
   $core.bool hasExpiresAt() => $_has(5);
   @$pb.TagNumber(6)
   void clearExpiresAt() => clearField(6);
   @$pb.TagNumber(6)
-  $0.Timestamp ensureExpiresAt() => $_ensure(5);
+  $27.Timestamp ensureExpiresAt() => $_ensure(5);
 
   @$pb.TagNumber(7)
   $core.String get refreshToken => $_getSZ(6);
@@ -157,15 +157,15 @@ class Session extends $pb.GeneratedMessage {
   void clearRefreshToken() => clearField(7);
 
   @$pb.TagNumber(8)
-  $0.Timestamp get createdAt => $_getN(7);
+  $27.Timestamp get createdAt => $_getN(7);
   @$pb.TagNumber(8)
-  set createdAt($0.Timestamp v) { setField(8, v); }
+  set createdAt($27.Timestamp v) { setField(8, v); }
   @$pb.TagNumber(8)
   $core.bool hasCreatedAt() => $_has(7);
   @$pb.TagNumber(8)
   void clearCreatedAt() => clearField(8);
   @$pb.TagNumber(8)
-  $0.Timestamp ensureCreatedAt() => $_ensure(7);
+  $27.Timestamp ensureCreatedAt() => $_ensure(7);
 }
 
 
diff --git a/frontend/app/lib/pb/session.pbserver.dart b/frontend/app/lib/pb/session.pbserver.dart
deleted file mode 100644
index 79ba84d..0000000
--- a/frontend/app/lib/pb/session.pbserver.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-//
-//  Generated code. Do not modify.
-//  source: session.proto
-//
-// @dart = 2.12
-
-// ignore_for_file: annotate_overrides, camel_case_types, comment_references
-// ignore_for_file: constant_identifier_names
-// ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
-// ignore_for_file: non_constant_identifier_names, prefer_final_fields
-// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
-
-export 'session.pb.dart';
-

From be41924b3b62a018efadb69b92b3bbc26c15a5d4 Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Tue, 24 Oct 2023 18:22:36 +0200
Subject: [PATCH 03/24] ft/adds logo and background image

---
 .../app/lib/assets/hero-pattern-300x200.png   | Bin 0 -> 15699 bytes
 frontend/app/lib/assets/logo_300x200.png      | Bin 0 -> 5049 bytes
 frontend/app/lib/main.dart                    |   7 +-
 frontend/app/lib/pages/main_screen.dart       |  60 ++++++++++++++----
 frontend/app/pubspec.yaml                     |   4 +-
 5 files changed, 57 insertions(+), 14 deletions(-)
 create mode 100644 frontend/app/lib/assets/hero-pattern-300x200.png
 create mode 100644 frontend/app/lib/assets/logo_300x200.png

diff --git a/frontend/app/lib/assets/hero-pattern-300x200.png b/frontend/app/lib/assets/hero-pattern-300x200.png
new file mode 100644
index 0000000000000000000000000000000000000000..69a8390ca22c550a1543b51b332ca4b3bbb21866
GIT binary patch
literal 15699
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
FV1moH$=d(`

literal 0
HcmV?d00001

diff --git a/frontend/app/lib/assets/logo_300x200.png b/frontend/app/lib/assets/logo_300x200.png
new file mode 100644
index 0000000000000000000000000000000000000000..0b4ca41caa03bba7069252141a5cf13fd30d4cf8
GIT binary patch
literal 5049
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

literal 0
HcmV?d00001

diff --git a/frontend/app/lib/main.dart b/frontend/app/lib/main.dart
index bc298a4..19489d1 100644
--- a/frontend/app/lib/main.dart
+++ b/frontend/app/lib/main.dart
@@ -2,6 +2,9 @@ import 'package:flutter/material.dart';
 
 import 'package:app/pages/main_screen.dart';
 
-void main() {
-  runApp(MaterialApp(home: MainScreen()));
+void main() async {
+  WidgetsFlutterBinding.ensureInitialized();
+  runApp(MaterialApp(
+    home: MainScreen(),
+  ));
 }
diff --git a/frontend/app/lib/pages/main_screen.dart b/frontend/app/lib/pages/main_screen.dart
index 6719e77..615e60d 100644
--- a/frontend/app/lib/pages/main_screen.dart
+++ b/frontend/app/lib/pages/main_screen.dart
@@ -15,17 +15,55 @@ class MainScreen extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return Scaffold(
-      body: Column(
-        mainAxisAlignment: MainAxisAlignment.center,
-        crossAxisAlignment: CrossAxisAlignment.center,
-        children: [
-          TextButton(
-              onPressed: () {
-                test();
-              },
-              child: const Text('Button'))
-        ],
+    return Container(
+      decoration: const BoxDecoration(
+        // color: Color.fromARGB(230, 255, 255, 255),
+        gradient: LinearGradient(
+          colors: [Colors.black, Colors.white],
+          begin: Alignment.topCenter,
+          end: Alignment.bottomCenter,
+        ),
+        image: DecorationImage(
+          image: AssetImage(
+            'lib/assets/hero-pattern-300x200.png',
+            // color: Colors.grey,
+          ),
+          repeat: ImageRepeat.repeat,
+          fit: BoxFit.contain,
+        ),
+      ),
+      child: Scaffold(
+        backgroundColor: Colors.transparent,
+        appBar: AppBar(
+          backgroundColor: Colors.black,
+          flexibleSpace: Image.asset(
+            'lib/assets/logo_300x200.png',
+            height: 80,
+          ),
+          actions: [
+            IconButton(
+              onPressed: () {},
+              icon: const Icon(Icons.menu),
+              tooltip: 'Menu',
+            ),
+            // IconButton(
+            //   onPressed: () {},
+            //   icon: const Icon(Icons.login_sharp),
+            //   tooltip: 'Login',
+            // ),
+          ],
+        ),
+        body: Column(
+          mainAxisAlignment: MainAxisAlignment.center,
+          crossAxisAlignment: CrossAxisAlignment.center,
+          children: [
+            TextButton(
+                onPressed: () {
+                  test();
+                },
+                child: const Text('Button'))
+          ],
+        ),
       ),
     );
   }
diff --git a/frontend/app/pubspec.yaml b/frontend/app/pubspec.yaml
index 0372b7a..6b33b3f 100644
--- a/frontend/app/pubspec.yaml
+++ b/frontend/app/pubspec.yaml
@@ -64,7 +64,9 @@ flutter:
   uses-material-design: true
 
   # To add assets to your application, add an assets section, like this:
-  # assets:
+  assets:
+    - lib/assets/logo_300x200.png
+    - lib/assets/hero-pattern-300x200.png
   #   - images/a_dot_burr.jpeg
   #   - images/a_dot_ham.jpeg
 

From a14b87012ad7cf062902b44bb20ae54370ff3915 Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Wed, 25 Oct 2023 00:00:39 +0200
Subject: [PATCH 04/24] ft/adds login_screen and initial home_screen

---
 frontend/app/lib/gapi/client.dart        |  46 ++++++++++
 frontend/app/lib/main.dart               |   7 ++
 frontend/app/lib/pages/home_screen.dart  |  23 +++++
 frontend/app/lib/pages/login_screen.dart | 102 +++++++++++++++++++++++
 frontend/app/lib/pages/main_screen.dart  |  27 +++---
 5 files changed, 190 insertions(+), 15 deletions(-)
 create mode 100644 frontend/app/lib/pages/home_screen.dart
 create mode 100644 frontend/app/lib/pages/login_screen.dart

diff --git a/frontend/app/lib/gapi/client.dart b/frontend/app/lib/gapi/client.dart
index 91abab8..ccd0006 100644
--- a/frontend/app/lib/gapi/client.dart
+++ b/frontend/app/lib/gapi/client.dart
@@ -1,6 +1,10 @@
+import 'package:app/main.dart';
 import 'package:app/pb/rpc_create_account.pb.dart';
+import 'package:app/pb/rpc_get_account_info.pb.dart';
+import 'package:app/pb/rpc_login.pb.dart';
 import 'package:app/pb/service_df.pbgrpc.dart';
 import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
 import 'package:grpc/grpc.dart';
 
 class Client {
@@ -30,4 +34,46 @@ class Client {
     }
     return CreateAccountResponse();
   }
+
+  // LoginResponse Login(BuildContext context, LoginRequest request ){
+  //   try {
+  //     final response = stub.login(request);
+  //     return response;
+  //   } catch (e) {
+  //     ScaffoldMessenger.of(context).showSnackBar(SnackBar(
+  //                   content: Text('Login fehlgeschlagen: $e'),
+  //                 ));
+  //   }
+  //   return LoginResponse();
+
+  // }
+
+  Future<LoginResponse> login(LoginRequest request, {Function? onError}) async {
+    try {
+      final response = await stub.login(request);
+      return response;
+    } on GrpcError catch (e) {
+      print('caught error: ${e.message}');
+      onError!();
+    } catch (e) {
+      print('caught error: $e');
+      onError!();
+    }
+    return LoginResponse();
+  }
+
+  Future<GetAccountInfoResponse> getAccountInfo(GetAccountInfoRequest request,
+      {Function? onError}) async {
+    try {
+      final response = await stub.getAccountInfo(request);
+      return response;
+    } on GrpcError catch (e) {
+      print('caught error: ${e.message}');
+      onError!();
+    } catch (e) {
+      print('caught error: $e');
+      onError!();
+    }
+    return GetAccountInfoResponse();
+  }
 }
diff --git a/frontend/app/lib/main.dart b/frontend/app/lib/main.dart
index 19489d1..f2393fa 100644
--- a/frontend/app/lib/main.dart
+++ b/frontend/app/lib/main.dart
@@ -2,9 +2,16 @@ import 'package:flutter/material.dart';
 
 import 'package:app/pages/main_screen.dart';
 
+class GlobalVariable {
+  /// This global key is used in material app for navigation through firebase notifications.
+  static final GlobalKey<NavigatorState> navigatorState =
+      GlobalKey<NavigatorState>();
+}
+
 void main() async {
   WidgetsFlutterBinding.ensureInitialized();
   runApp(MaterialApp(
+    navigatorKey: GlobalVariable.navigatorState,
     home: MainScreen(),
   ));
 }
diff --git a/frontend/app/lib/pages/home_screen.dart b/frontend/app/lib/pages/home_screen.dart
new file mode 100644
index 0000000..a391ab6
--- /dev/null
+++ b/frontend/app/lib/pages/home_screen.dart
@@ -0,0 +1,23 @@
+import 'package:app/pb/account_info.pb.dart';
+import 'package:flutter/material.dart';
+
+class HomeScreen extends StatelessWidget {
+  HomeScreen({super.key, required this.account_info});
+
+  AccountInfo account_info;
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      children: [
+        Text(
+          'Willkommen ${account_info.firstname}!',
+          style: const TextStyle(
+            fontSize: 30,
+            fontWeight: FontWeight.bold,
+          ),
+        )
+      ],
+    );
+  }
+}
diff --git a/frontend/app/lib/pages/login_screen.dart b/frontend/app/lib/pages/login_screen.dart
new file mode 100644
index 0000000..4a035b7
--- /dev/null
+++ b/frontend/app/lib/pages/login_screen.dart
@@ -0,0 +1,102 @@
+import 'package:app/gapi/client.dart';
+import 'package:app/pages/home_screen.dart';
+import 'package:app/pb/rpc_get_account_info.pb.dart';
+import 'package:app/pb/rpc_login.pb.dart';
+import 'package:flutter/material.dart';
+
+class LoginScreen extends StatelessWidget {
+  LoginScreen({super.key});
+
+  Client client = Client();
+
+  final _formKey = GlobalKey<FormState>();
+  final mailController = TextEditingController();
+  final passwordController = TextEditingController();
+
+  @override
+  Widget build(BuildContext context) {
+    return Form(
+      key: _formKey,
+      child: Column(
+        mainAxisAlignment: MainAxisAlignment.center,
+        crossAxisAlignment: CrossAxisAlignment.center,
+        children: [
+          TextFormField(
+            style: const TextStyle(
+              color: Colors.white,
+            ),
+            controller: mailController,
+            decoration: const InputDecoration(
+              fillColor: Color.fromARGB(30, 255, 255, 255),
+              filled: true,
+              hintStyle: TextStyle(
+                color: Colors.white38,
+              ),
+              hintText: 'E-Mail Adresse',
+            ),
+            keyboardType: TextInputType.emailAddress,
+            validator: (value) {
+              if (value == null || value.isEmpty) {
+                return 'Bitte eine gültige E-Mail Adresse eingeben';
+              }
+              return null;
+            },
+          ),
+          TextFormField(
+            style: const TextStyle(
+              color: Colors.white,
+            ),
+            controller: passwordController,
+            decoration: const InputDecoration(
+              fillColor: Color.fromARGB(30, 255, 255, 255),
+              filled: true,
+              hintStyle: TextStyle(
+                color: Colors.white38,
+              ),
+              hintText: 'Passwort',
+            ),
+            keyboardType: TextInputType.visiblePassword,
+            obscureText: true,
+            validator: (value) {
+              if (value == null || value.isEmpty) {
+                return 'Bitte geben Sie Ihr Passwort ein';
+              }
+              return null;
+            },
+          ),
+          ElevatedButton(
+              onPressed: () async {
+                if (_formKey.currentState!.validate()) {
+                  // final navigator = Navigator.of(context);
+                  LoginResponse response = await client.login(
+                    LoginRequest(
+                      email: mailController.text,
+                      password: passwordController.text,
+                    ),
+                    onError: () {
+                      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
+                        content: Text('Login fehlgeschlagen'),
+                      ));
+                    },
+                  );
+
+                  print(response);
+
+                  //   GetAccountInfoResponse resp = await client.getAccountInfo(
+                  //       GetAccountInfoRequest(accountId: response.accountId));
+                  //   Navigator.push(
+                  //     context,
+                  //     MaterialPageRoute(
+                  //       builder: (context) => HomeScreen(
+                  //         account_info: resp.accountInfo,
+                  //       ),
+                  //     ),
+                  //   );
+                }
+              },
+              child: const Icon(Icons.arrow_forward))
+        ],
+      ),
+    );
+  }
+}
diff --git a/frontend/app/lib/pages/main_screen.dart b/frontend/app/lib/pages/main_screen.dart
index 615e60d..53e18e9 100644
--- a/frontend/app/lib/pages/main_screen.dart
+++ b/frontend/app/lib/pages/main_screen.dart
@@ -1,16 +1,21 @@
 import 'package:app/gapi/client.dart';
-import 'package:app/pb/rpc_create_account.pb.dart';
+import 'package:app/pages/login_screen.dart';
 import 'package:flutter/material.dart';
 
+Map<String, Widget> screens = {
+  // 'main': MainScreen(),
+  'login': LoginScreen(),
+};
+
 class MainScreen extends StatelessWidget {
   MainScreen({super.key});
 
   Client client = Client();
 
-  void test() {
-    client.stub.createAccount(
-      CreateAccountRequest(email: "dev@itsscb.de", password: "secret-key123"),
-    );
+  String currentScreen = 'login';
+
+  setPage(String screen) {
+    currentScreen = screen;
   }
 
   @override
@@ -53,16 +58,8 @@ class MainScreen extends StatelessWidget {
             // ),
           ],
         ),
-        body: Column(
-          mainAxisAlignment: MainAxisAlignment.center,
-          crossAxisAlignment: CrossAxisAlignment.center,
-          children: [
-            TextButton(
-                onPressed: () {
-                  test();
-                },
-                child: const Text('Button'))
-          ],
+        body: Center(
+          child: screens[currentScreen],
         ),
       ),
     );

From d0687e2d3f61e9d9eb4ad0d92d75d96c4be16a7d Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Thu, 26 Oct 2023 03:32:07 +0200
Subject: [PATCH 05/24] ft/adds dashboard screen and refactores

adds:
- loading screen
- global background image

refactores:
- no more screens, just pages

fixes:
- login callback functions
---
 frontend/app/lib/gapi/client.dart          |  61 +++----
 frontend/app/lib/main.dart                 |  42 +++--
 frontend/app/lib/pages/dashboard_page.dart |  62 +++++++
 frontend/app/lib/pages/home_screen.dart    |  23 ---
 frontend/app/lib/pages/login_page.dart     | 179 +++++++++++++++++++++
 frontend/app/lib/pages/login_screen.dart   | 102 ------------
 frontend/app/lib/pages/main_screen.dart    |  67 --------
 frontend/app/lib/widgets/background.dart   |  29 ++++
 8 files changed, 334 insertions(+), 231 deletions(-)
 create mode 100644 frontend/app/lib/pages/dashboard_page.dart
 delete mode 100644 frontend/app/lib/pages/home_screen.dart
 create mode 100644 frontend/app/lib/pages/login_page.dart
 delete mode 100644 frontend/app/lib/pages/login_screen.dart
 delete mode 100644 frontend/app/lib/pages/main_screen.dart
 create mode 100644 frontend/app/lib/widgets/background.dart

diff --git a/frontend/app/lib/gapi/client.dart b/frontend/app/lib/gapi/client.dart
index ccd0006..5cd6d75 100644
--- a/frontend/app/lib/gapi/client.dart
+++ b/frontend/app/lib/gapi/client.dart
@@ -1,16 +1,16 @@
-import 'package:app/main.dart';
 import 'package:app/pb/rpc_create_account.pb.dart';
 import 'package:app/pb/rpc_get_account_info.pb.dart';
 import 'package:app/pb/rpc_login.pb.dart';
 import 'package:app/pb/service_df.pbgrpc.dart';
-import 'package:flutter/foundation.dart';
-import 'package:flutter/material.dart';
 import 'package:grpc/grpc.dart';
 
 class Client {
   String baseUrl = 'localhost';
   int port = 9090;
 
+  Map<String, dynamic> metadata = {'Authorization': ''};
+  String accessToken = '';
+
   dfClient stub = dfClient(
     ClientChannel('10.0.2.2',
         port: 9090,
@@ -35,44 +35,51 @@ class Client {
     return CreateAccountResponse();
   }
 
-  // LoginResponse Login(BuildContext context, LoginRequest request ){
-  //   try {
-  //     final response = stub.login(request);
-  //     return response;
-  //   } catch (e) {
-  //     ScaffoldMessenger.of(context).showSnackBar(SnackBar(
-  //                   content: Text('Login fehlgeschlagen: $e'),
-  //                 ));
-  //   }
-  //   return LoginResponse();
-
-  // }
-
-  Future<LoginResponse> login(LoginRequest request, {Function? onError}) async {
+  Future<LoginResponse> login(
+      {required String email,
+      required String password,
+      required Function onError,
+      required Function onSuccess}) async {
+    LoginResponse response = LoginResponse();
     try {
-      final response = await stub.login(request);
-      return response;
+      response = await stub.login(LoginRequest(
+        email: email,
+        password: password,
+      ));
+      accessToken = response.accessToken;
+      metadata['Authorization'] = 'Bearer ${response.accessToken}';
+      print('auth: ${metadata['Authorization']}');
+      onSuccess();
+      // return response;
     } on GrpcError catch (e) {
       print('caught error: ${e.message}');
-      onError!();
+      metadata['Authorization'] = '';
+      onError();
     } catch (e) {
-      print('caught error: $e');
-      onError!();
+      print('caught error: ${e}');
+      metadata['Authorization'] = '';
+      onError();
     }
-    return LoginResponse();
+    return response;
   }
 
   Future<GetAccountInfoResponse> getAccountInfo(GetAccountInfoRequest request,
-      {Function? onError}) async {
+      {required String token, required Function onError}) async {
     try {
-      final response = await stub.getAccountInfo(request);
+      Map<String, String> metadata = {'Authorization': 'Bearer $token'};
+      final response = await stub.getAccountInfo(
+        request,
+        options: CallOptions(
+          metadata: metadata,
+        ),
+      );
       return response;
     } on GrpcError catch (e) {
       print('caught error: ${e.message}');
-      onError!();
+      onError();
     } catch (e) {
       print('caught error: $e');
-      onError!();
+      onError();
     }
     return GetAccountInfoResponse();
   }
diff --git a/frontend/app/lib/main.dart b/frontend/app/lib/main.dart
index f2393fa..409b5fb 100644
--- a/frontend/app/lib/main.dart
+++ b/frontend/app/lib/main.dart
@@ -1,17 +1,35 @@
+import 'package:app/pages/login_page.dart';
+import 'package:app/widgets/background.dart';
 import 'package:flutter/material.dart';
 
-import 'package:app/pages/main_screen.dart';
-
-class GlobalVariable {
-  /// This global key is used in material app for navigation through firebase notifications.
-  static final GlobalKey<NavigatorState> navigatorState =
-      GlobalKey<NavigatorState>();
-}
-
 void main() async {
   WidgetsFlutterBinding.ensureInitialized();
-  runApp(MaterialApp(
-    navigatorKey: GlobalVariable.navigatorState,
-    home: MainScreen(),
-  ));
+
+  runApp(
+    MaterialApp(
+      theme: ThemeData().copyWith(
+          textTheme: const TextTheme().copyWith(
+            titleLarge: const TextStyle(
+              color: Colors.white,
+            ),
+            titleMedium: const TextStyle(
+              color: Colors.white,
+            ),
+            titleSmall: const TextStyle(
+              color: Colors.white,
+            ),
+          ),
+          inputDecorationTheme: const InputDecorationTheme(
+            labelStyle: TextStyle(
+              color: Colors.white,
+            ),
+          ),
+          scaffoldBackgroundColor: Colors.transparent,
+          appBarTheme: const AppBarTheme().copyWith(
+            backgroundColor: Colors.black,
+            foregroundColor: Colors.white,
+          )),
+      home: Background(child: LoginPage()),
+    ),
+  );
 }
diff --git a/frontend/app/lib/pages/dashboard_page.dart b/frontend/app/lib/pages/dashboard_page.dart
new file mode 100644
index 0000000..2a5cfb1
--- /dev/null
+++ b/frontend/app/lib/pages/dashboard_page.dart
@@ -0,0 +1,62 @@
+import 'package:app/gapi/client.dart';
+import 'package:flutter/material.dart';
+
+class DashboardPage extends StatefulWidget {
+  DashboardPage({super.key, required this.client});
+
+  final Client client;
+
+  @override
+  State<DashboardPage> createState() => _DashboardPageState();
+}
+
+class _DashboardPageState extends State<DashboardPage> {
+  bool _loading = false;
+
+  void _setLoading(bool loading) {
+    setState(() {
+      _loading = loading;
+    });
+  }
+
+  @override
+  void initState() {
+    super.initState();
+    if (widget.client.accessToken == '') {
+      Navigator.of(context).pop();
+    }
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    print(widget.client.accessToken);
+    return Scaffold(
+      appBar: AppBar(
+        automaticallyImplyLeading: false,
+        backgroundColor: Colors.black,
+        flexibleSpace: Image.asset(
+          'lib/assets/logo_300x200.png',
+          height: 80,
+        ),
+        // actions: [
+        //   IconButton(
+        //     onPressed: () {},
+        //     icon: const Icon(Icons.menu),
+        //     tooltip: 'Menu',
+        //   ),
+        // IconButton(
+        //   onPressed: () {},
+        //   icon: const Icon(Icons.login_sharp),
+        //   tooltip: 'Login',
+        // ),
+        // ],
+      ),
+      body: Text(
+        widget.client.accessToken,
+        style: const TextStyle(
+          color: Colors.white,
+        ),
+      ),
+    );
+  }
+}
diff --git a/frontend/app/lib/pages/home_screen.dart b/frontend/app/lib/pages/home_screen.dart
deleted file mode 100644
index a391ab6..0000000
--- a/frontend/app/lib/pages/home_screen.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-import 'package:app/pb/account_info.pb.dart';
-import 'package:flutter/material.dart';
-
-class HomeScreen extends StatelessWidget {
-  HomeScreen({super.key, required this.account_info});
-
-  AccountInfo account_info;
-
-  @override
-  Widget build(BuildContext context) {
-    return Column(
-      children: [
-        Text(
-          'Willkommen ${account_info.firstname}!',
-          style: const TextStyle(
-            fontSize: 30,
-            fontWeight: FontWeight.bold,
-          ),
-        )
-      ],
-    );
-  }
-}
diff --git a/frontend/app/lib/pages/login_page.dart b/frontend/app/lib/pages/login_page.dart
new file mode 100644
index 0000000..4789cee
--- /dev/null
+++ b/frontend/app/lib/pages/login_page.dart
@@ -0,0 +1,179 @@
+import 'package:app/gapi/client.dart';
+import 'package:app/pages/dashboard_page.dart';
+import 'package:app/pb/rpc_login.pb.dart';
+import 'package:flutter/material.dart';
+
+class LoginPage extends StatefulWidget {
+  const LoginPage({super.key});
+
+  @override
+  State<LoginPage> createState() => _LoginPageState();
+}
+
+class _LoginPageState extends State<LoginPage> {
+  bool _loading = false;
+
+  void _setLoading(bool loading) {
+    setState(() {
+      _loading = loading;
+    });
+  }
+
+  final Client client = Client();
+
+  final _formKey = GlobalKey<FormState>();
+  final mailController = TextEditingController();
+  final passwordController = TextEditingController();
+
+  // @override
+  // void initState() {
+  //   super.initState();
+  // }
+
+  // Future<String> _login(
+  //     {required BuildContext context,
+  //     required String email,
+  //     required String password,
+  //     required Function onSuccess,
+  //     required Function onError}) async {
+  //   LoginResponse r = await client.login(
+  //     LoginRequest(
+  //       email: email,
+  //       password: password,
+  //     ),
+  //     onError: onError,
+  //     onSuccess: onSuccess,
+  //   );
+  //   return r.accessToken;
+  // }
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(
+        automaticallyImplyLeading: false,
+        backgroundColor: Colors.black,
+        flexibleSpace: Image.asset(
+          'lib/assets/logo_300x200.png',
+          height: 80,
+        ),
+        // actions: [
+        //   IconButton(
+        //     onPressed: () {},
+        //     icon: const Icon(Icons.menu),
+        //     tooltip: 'Menu',
+        //   ),
+        // IconButton(
+        //   onPressed: () {},
+        //   icon: const Icon(Icons.login_sharp),
+        //   tooltip: 'Login',
+        // ),
+        // ],
+      ),
+      body: !_loading
+          ? Form(
+              key: _formKey,
+              child: Column(
+                mainAxisAlignment: MainAxisAlignment.center,
+                crossAxisAlignment: CrossAxisAlignment.center,
+                children: [
+                  TextFormField(
+                    style: TextStyle(
+                      color: Theme.of(context).colorScheme.primary,
+                    ),
+                    controller: mailController,
+                    decoration: const InputDecoration(
+                      fillColor: Color.fromARGB(30, 255, 255, 255),
+                      filled: true,
+                      hintStyle: TextStyle(
+                        color: Colors.white38,
+                      ),
+                      hintText: 'E-Mail Adresse',
+                    ),
+                    keyboardType: TextInputType.emailAddress,
+                    validator: (value) {
+                      if (value == null || value.isEmpty) {
+                        return 'Bitte eine gültige E-Mail Adresse eingeben';
+                      }
+                      return null;
+                    },
+                  ),
+                  TextFormField(
+                    style: const TextStyle(
+                      color: Colors.white,
+                    ),
+                    controller: passwordController,
+                    decoration: const InputDecoration(
+                      fillColor: Color.fromARGB(30, 255, 255, 255),
+                      filled: true,
+                      hintStyle: TextStyle(
+                        color: Colors.white38,
+                      ),
+                      hintText: 'Passwort',
+                    ),
+                    keyboardType: TextInputType.visiblePassword,
+                    obscureText: true,
+                    validator: (value) {
+                      if (value == null || value.isEmpty) {
+                        return 'Bitte geben Sie Ihr Passwort ein';
+                      }
+                      return null;
+                    },
+                  ),
+                  ElevatedButton(
+                      onPressed: () {
+                        if (_formKey.currentState!.validate()) {
+                          // final navigator = Navigator.of(context);
+                          _setLoading(true);
+                          client
+                              .login(
+                            email: mailController.text,
+                            password: passwordController.text,
+                            onError: () {
+                              _setLoading(false);
+                              ScaffoldMessenger.of(context)
+                                  .showSnackBar(const SnackBar(
+                                content: Text('Login fehlgeschlagen'),
+                              ));
+                            },
+                            onSuccess: () {
+                              // _setLoading(false);
+                              ScaffoldMessenger.of(context)
+                                  .showSnackBar(const SnackBar(
+                                content: Text('Login erfolgreich'),
+                              ));
+                            },
+                          )
+                              .then(
+                            (r) {
+                              if (r.accessToken != '') {
+                                Navigator.pushAndRemoveUntil(
+                                    context,
+                                    MaterialPageRoute(
+                                      builder: (ctx) => DashboardPage(
+                                        client: client,
+                                      ),
+                                    ),
+                                    (route) => false);
+                              }
+                              // _setLoading(false);
+                            },
+                          );
+                        }
+                      },
+                      child: const Icon(Icons.arrow_forward))
+                ],
+              ),
+            )
+          : Column(
+              mainAxisAlignment: MainAxisAlignment.center,
+              children: [
+                Image.asset(
+                  'lib/assets/logo_300x200.png',
+                  height: 300,
+                ),
+              ],
+            ),
+    );
+  }
+}
diff --git a/frontend/app/lib/pages/login_screen.dart b/frontend/app/lib/pages/login_screen.dart
deleted file mode 100644
index 4a035b7..0000000
--- a/frontend/app/lib/pages/login_screen.dart
+++ /dev/null
@@ -1,102 +0,0 @@
-import 'package:app/gapi/client.dart';
-import 'package:app/pages/home_screen.dart';
-import 'package:app/pb/rpc_get_account_info.pb.dart';
-import 'package:app/pb/rpc_login.pb.dart';
-import 'package:flutter/material.dart';
-
-class LoginScreen extends StatelessWidget {
-  LoginScreen({super.key});
-
-  Client client = Client();
-
-  final _formKey = GlobalKey<FormState>();
-  final mailController = TextEditingController();
-  final passwordController = TextEditingController();
-
-  @override
-  Widget build(BuildContext context) {
-    return Form(
-      key: _formKey,
-      child: Column(
-        mainAxisAlignment: MainAxisAlignment.center,
-        crossAxisAlignment: CrossAxisAlignment.center,
-        children: [
-          TextFormField(
-            style: const TextStyle(
-              color: Colors.white,
-            ),
-            controller: mailController,
-            decoration: const InputDecoration(
-              fillColor: Color.fromARGB(30, 255, 255, 255),
-              filled: true,
-              hintStyle: TextStyle(
-                color: Colors.white38,
-              ),
-              hintText: 'E-Mail Adresse',
-            ),
-            keyboardType: TextInputType.emailAddress,
-            validator: (value) {
-              if (value == null || value.isEmpty) {
-                return 'Bitte eine gültige E-Mail Adresse eingeben';
-              }
-              return null;
-            },
-          ),
-          TextFormField(
-            style: const TextStyle(
-              color: Colors.white,
-            ),
-            controller: passwordController,
-            decoration: const InputDecoration(
-              fillColor: Color.fromARGB(30, 255, 255, 255),
-              filled: true,
-              hintStyle: TextStyle(
-                color: Colors.white38,
-              ),
-              hintText: 'Passwort',
-            ),
-            keyboardType: TextInputType.visiblePassword,
-            obscureText: true,
-            validator: (value) {
-              if (value == null || value.isEmpty) {
-                return 'Bitte geben Sie Ihr Passwort ein';
-              }
-              return null;
-            },
-          ),
-          ElevatedButton(
-              onPressed: () async {
-                if (_formKey.currentState!.validate()) {
-                  // final navigator = Navigator.of(context);
-                  LoginResponse response = await client.login(
-                    LoginRequest(
-                      email: mailController.text,
-                      password: passwordController.text,
-                    ),
-                    onError: () {
-                      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
-                        content: Text('Login fehlgeschlagen'),
-                      ));
-                    },
-                  );
-
-                  print(response);
-
-                  //   GetAccountInfoResponse resp = await client.getAccountInfo(
-                  //       GetAccountInfoRequest(accountId: response.accountId));
-                  //   Navigator.push(
-                  //     context,
-                  //     MaterialPageRoute(
-                  //       builder: (context) => HomeScreen(
-                  //         account_info: resp.accountInfo,
-                  //       ),
-                  //     ),
-                  //   );
-                }
-              },
-              child: const Icon(Icons.arrow_forward))
-        ],
-      ),
-    );
-  }
-}
diff --git a/frontend/app/lib/pages/main_screen.dart b/frontend/app/lib/pages/main_screen.dart
deleted file mode 100644
index 53e18e9..0000000
--- a/frontend/app/lib/pages/main_screen.dart
+++ /dev/null
@@ -1,67 +0,0 @@
-import 'package:app/gapi/client.dart';
-import 'package:app/pages/login_screen.dart';
-import 'package:flutter/material.dart';
-
-Map<String, Widget> screens = {
-  // 'main': MainScreen(),
-  'login': LoginScreen(),
-};
-
-class MainScreen extends StatelessWidget {
-  MainScreen({super.key});
-
-  Client client = Client();
-
-  String currentScreen = 'login';
-
-  setPage(String screen) {
-    currentScreen = screen;
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    return Container(
-      decoration: const BoxDecoration(
-        // color: Color.fromARGB(230, 255, 255, 255),
-        gradient: LinearGradient(
-          colors: [Colors.black, Colors.white],
-          begin: Alignment.topCenter,
-          end: Alignment.bottomCenter,
-        ),
-        image: DecorationImage(
-          image: AssetImage(
-            'lib/assets/hero-pattern-300x200.png',
-            // color: Colors.grey,
-          ),
-          repeat: ImageRepeat.repeat,
-          fit: BoxFit.contain,
-        ),
-      ),
-      child: Scaffold(
-        backgroundColor: Colors.transparent,
-        appBar: AppBar(
-          backgroundColor: Colors.black,
-          flexibleSpace: Image.asset(
-            'lib/assets/logo_300x200.png',
-            height: 80,
-          ),
-          actions: [
-            IconButton(
-              onPressed: () {},
-              icon: const Icon(Icons.menu),
-              tooltip: 'Menu',
-            ),
-            // IconButton(
-            //   onPressed: () {},
-            //   icon: const Icon(Icons.login_sharp),
-            //   tooltip: 'Login',
-            // ),
-          ],
-        ),
-        body: Center(
-          child: screens[currentScreen],
-        ),
-      ),
-    );
-  }
-}
diff --git a/frontend/app/lib/widgets/background.dart b/frontend/app/lib/widgets/background.dart
new file mode 100644
index 0000000..b0232a3
--- /dev/null
+++ b/frontend/app/lib/widgets/background.dart
@@ -0,0 +1,29 @@
+import 'package:flutter/material.dart';
+
+class Background extends StatelessWidget {
+  const Background({super.key, required this.child});
+
+  final Widget child;
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+        decoration: const BoxDecoration(
+          // color: Color.fromARGB(230, 255, 255, 255),
+          gradient: LinearGradient(
+            colors: [Colors.black, Colors.white],
+            begin: Alignment.topCenter,
+            end: Alignment.bottomCenter,
+          ),
+          image: DecorationImage(
+            image: AssetImage(
+              'lib/assets/hero-pattern-300x200.png',
+              // color: Colors.grey,
+            ),
+            repeat: ImageRepeat.repeat,
+            fit: BoxFit.contain,
+          ),
+        ),
+        child: child);
+  }
+}

From 35d8ed02210c21a218b9921467d8b76e1bb8327c Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Thu, 26 Oct 2023 03:55:48 +0200
Subject: [PATCH 06/24] ft/adds background widget to dashboard_page

---
 frontend/app/lib/main.dart                 |  2 +-
 frontend/app/lib/pages/dashboard_page.dart | 17 ++++++++++++-----
 frontend/app/lib/pages/login_page.dart     |  1 -
 3 files changed, 13 insertions(+), 7 deletions(-)

diff --git a/frontend/app/lib/main.dart b/frontend/app/lib/main.dart
index 409b5fb..20d7689 100644
--- a/frontend/app/lib/main.dart
+++ b/frontend/app/lib/main.dart
@@ -29,7 +29,7 @@ void main() async {
             backgroundColor: Colors.black,
             foregroundColor: Colors.white,
           )),
-      home: Background(child: LoginPage()),
+      home: const Background(child: LoginPage()),
     ),
   );
 }
diff --git a/frontend/app/lib/pages/dashboard_page.dart b/frontend/app/lib/pages/dashboard_page.dart
index 2a5cfb1..46e9562 100644
--- a/frontend/app/lib/pages/dashboard_page.dart
+++ b/frontend/app/lib/pages/dashboard_page.dart
@@ -1,4 +1,5 @@
 import 'package:app/gapi/client.dart';
+import 'package:app/widgets/background.dart';
 import 'package:flutter/material.dart';
 
 class DashboardPage extends StatefulWidget {
@@ -33,7 +34,7 @@ class _DashboardPageState extends State<DashboardPage> {
     return Scaffold(
       appBar: AppBar(
         automaticallyImplyLeading: false,
-        backgroundColor: Colors.black,
+        // backgroundColor: Colors.black,
         flexibleSpace: Image.asset(
           'lib/assets/logo_300x200.png',
           height: 80,
@@ -51,10 +52,16 @@ class _DashboardPageState extends State<DashboardPage> {
         // ),
         // ],
       ),
-      body: Text(
-        widget.client.accessToken,
-        style: const TextStyle(
-          color: Colors.white,
+      body: Background(
+        child: Column(
+          children: [
+            Text(
+              widget.client.accessToken,
+              style: const TextStyle(
+                color: Colors.white,
+              ),
+            ),
+          ],
         ),
       ),
     );
diff --git a/frontend/app/lib/pages/login_page.dart b/frontend/app/lib/pages/login_page.dart
index 4789cee..3656ab4 100644
--- a/frontend/app/lib/pages/login_page.dart
+++ b/frontend/app/lib/pages/login_page.dart
@@ -52,7 +52,6 @@ class _LoginPageState extends State<LoginPage> {
     return Scaffold(
       appBar: AppBar(
         automaticallyImplyLeading: false,
-        backgroundColor: Colors.black,
         flexibleSpace: Image.asset(
           'lib/assets/logo_300x200.png',
           height: 80,

From a8377110bb48e7c928ce9c7958f33240981eef2b Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Thu, 26 Oct 2023 23:29:22 +0200
Subject: [PATCH 07/24] ft/adds automatic download of data in initState and
 more

---
 frontend/app/lib/gapi/client.dart            | 10 ++-
 frontend/app/lib/main.dart                   | 15 +++-
 frontend/app/lib/pages/dashboard_page.dart   | 87 +++++++++++++++++---
 frontend/app/lib/pages/login_page.dart       | 73 ++++++----------
 frontend/app/lib/widgets/loading_widget.dart | 17 ++++
 5 files changed, 138 insertions(+), 64 deletions(-)
 create mode 100644 frontend/app/lib/widgets/loading_widget.dart

diff --git a/frontend/app/lib/gapi/client.dart b/frontend/app/lib/gapi/client.dart
index 5cd6d75..a27f966 100644
--- a/frontend/app/lib/gapi/client.dart
+++ b/frontend/app/lib/gapi/client.dart
@@ -1,3 +1,4 @@
+import 'package:fixnum/fixnum.dart';
 import 'package:app/pb/rpc_create_account.pb.dart';
 import 'package:app/pb/rpc_get_account_info.pb.dart';
 import 'package:app/pb/rpc_login.pb.dart';
@@ -8,8 +9,9 @@ class Client {
   String baseUrl = 'localhost';
   int port = 9090;
 
-  Map<String, dynamic> metadata = {'Authorization': ''};
+  Map<String, String> metadata = {'Authorization': ''};
   String accessToken = '';
+  Int64 accountId = Int64();
 
   dfClient stub = dfClient(
     ClientChannel('10.0.2.2',
@@ -25,7 +27,6 @@ class Client {
 
   Future<CreateAccountResponse> createAccount(
       CreateAccountRequest request) async {
-    // CreateAccountResponse response;
     try {
       final response = stub.createAccount(request);
       return response;
@@ -47,6 +48,7 @@ class Client {
         password: password,
       ));
       accessToken = response.accessToken;
+      accountId = response.accountId;
       metadata['Authorization'] = 'Bearer ${response.accessToken}';
       print('auth: ${metadata['Authorization']}');
       onSuccess();
@@ -64,9 +66,9 @@ class Client {
   }
 
   Future<GetAccountInfoResponse> getAccountInfo(GetAccountInfoRequest request,
-      {required String token, required Function onError}) async {
+      {required Function onError}) async {
     try {
-      Map<String, String> metadata = {'Authorization': 'Bearer $token'};
+      // Map<String, String> metadata = {'Authorization': 'Bearer $token'};
       final response = await stub.getAccountInfo(
         request,
         options: CallOptions(
diff --git a/frontend/app/lib/main.dart b/frontend/app/lib/main.dart
index 20d7689..537dffe 100644
--- a/frontend/app/lib/main.dart
+++ b/frontend/app/lib/main.dart
@@ -8,6 +8,19 @@ void main() async {
   runApp(
     MaterialApp(
       theme: ThemeData().copyWith(
+          colorScheme: const ColorScheme(
+            brightness: Brightness.dark,
+            primary: Colors.white,
+            onPrimary: Colors.black,
+            secondary: Colors.black,
+            onSecondary: Colors.white,
+            error: Color.fromARGB(170, 255, 0, 0),
+            onError: Color.fromARGB(170, 255, 0, 0),
+            background: Colors.transparent,
+            onBackground: Colors.white,
+            surface: Colors.black,
+            onSurface: Colors.white,
+          ),
           textTheme: const TextTheme().copyWith(
             titleLarge: const TextStyle(
               color: Colors.white,
@@ -21,7 +34,7 @@ void main() async {
           ),
           inputDecorationTheme: const InputDecorationTheme(
             labelStyle: TextStyle(
-              color: Colors.white,
+              color: Colors.grey,
             ),
           ),
           scaffoldBackgroundColor: Colors.transparent,
diff --git a/frontend/app/lib/pages/dashboard_page.dart b/frontend/app/lib/pages/dashboard_page.dart
index 46e9562..84bd1d4 100644
--- a/frontend/app/lib/pages/dashboard_page.dart
+++ b/frontend/app/lib/pages/dashboard_page.dart
@@ -1,5 +1,8 @@
 import 'package:app/gapi/client.dart';
+import 'package:app/pb/account_info.pb.dart';
+import 'package:app/pb/rpc_get_account_info.pb.dart';
 import 'package:app/widgets/background.dart';
+import 'package:app/widgets/loading_widget.dart';
 import 'package:flutter/material.dart';
 
 class DashboardPage extends StatefulWidget {
@@ -13,6 +16,7 @@ class DashboardPage extends StatefulWidget {
 
 class _DashboardPageState extends State<DashboardPage> {
   bool _loading = false;
+  late AccountInfo accountInfo;
 
   void _setLoading(bool loading) {
     setState(() {
@@ -25,16 +29,68 @@ class _DashboardPageState extends State<DashboardPage> {
     super.initState();
     if (widget.client.accessToken == '') {
       Navigator.of(context).pop();
+      return;
     }
+
+    _setLoading(true);
+    widget.client.getAccountInfo(
+      GetAccountInfoRequest(
+        accountId: widget.client.accountId,
+      ),
+      onError: () {
+        ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
+          content: Text('AccountInfo konnte nicht geladen werden'),
+        ));
+      },
+    ).then((value) {
+      accountInfo = value.accountInfo;
+      _setLoading(false);
+    });
   }
 
   @override
   Widget build(BuildContext context) {
     print(widget.client.accessToken);
     return Scaffold(
+      bottomNavigationBar: BottomNavigationBar(
+        items: const [
+          BottomNavigationBarItem(
+            label: '',
+            backgroundColor: Colors.white,
+            icon: Icon(
+              Icons.arrow_back,
+              color: Colors.white,
+            ),
+          ),
+          BottomNavigationBarItem(
+            backgroundColor: Colors.white,
+            label: '',
+            icon: Icon(
+              Icons.person,
+              color: Colors.white,
+            ),
+          ),
+          BottomNavigationBarItem(
+            backgroundColor: Colors.white,
+            label: '',
+            icon: Icon(
+              Icons.group,
+              color: Colors.white,
+            ),
+          ),
+          BottomNavigationBarItem(
+            backgroundColor: Colors.white,
+            label: '',
+            icon: Icon(
+              Icons.file_copy,
+              color: Colors.white,
+            ),
+          ),
+        ],
+        backgroundColor: Colors.transparent,
+      ),
       appBar: AppBar(
         automaticallyImplyLeading: false,
-        // backgroundColor: Colors.black,
         flexibleSpace: Image.asset(
           'lib/assets/logo_300x200.png',
           height: 80,
@@ -52,18 +108,25 @@ class _DashboardPageState extends State<DashboardPage> {
         // ),
         // ],
       ),
-      body: Background(
-        child: Column(
-          children: [
-            Text(
-              widget.client.accessToken,
-              style: const TextStyle(
-                color: Colors.white,
+      body: !_loading
+          ? Background(
+              child: Center(
+                child: Column(
+                  children: [
+                    const SizedBox(
+                      height: 48,
+                    ),
+                    Text(
+                      'Willkommen ${accountInfo.firstname} ${accountInfo.lastname}!',
+                      style: const TextStyle(
+                        fontSize: 24,
+                      ),
+                    ),
+                  ],
+                ),
               ),
-            ),
-          ],
-        ),
-      ),
+            )
+          : const LoadingWidget(),
     );
   }
 }
diff --git a/frontend/app/lib/pages/login_page.dart b/frontend/app/lib/pages/login_page.dart
index 3656ab4..89ddd00 100644
--- a/frontend/app/lib/pages/login_page.dart
+++ b/frontend/app/lib/pages/login_page.dart
@@ -1,6 +1,6 @@
 import 'package:app/gapi/client.dart';
 import 'package:app/pages/dashboard_page.dart';
-import 'package:app/pb/rpc_login.pb.dart';
+import 'package:app/widgets/loading_widget.dart';
 import 'package:flutter/material.dart';
 
 class LoginPage extends StatefulWidget {
@@ -25,28 +25,6 @@ class _LoginPageState extends State<LoginPage> {
   final mailController = TextEditingController();
   final passwordController = TextEditingController();
 
-  // @override
-  // void initState() {
-  //   super.initState();
-  // }
-
-  // Future<String> _login(
-  //     {required BuildContext context,
-  //     required String email,
-  //     required String password,
-  //     required Function onSuccess,
-  //     required Function onError}) async {
-  //   LoginResponse r = await client.login(
-  //     LoginRequest(
-  //       email: email,
-  //       password: password,
-  //     ),
-  //     onError: onError,
-  //     onSuccess: onSuccess,
-  //   );
-  //   return r.accessToken;
-  // }
-
   @override
   Widget build(BuildContext context) {
     return Scaffold(
@@ -56,18 +34,27 @@ class _LoginPageState extends State<LoginPage> {
           'lib/assets/logo_300x200.png',
           height: 80,
         ),
-        // actions: [
-        //   IconButton(
-        //     onPressed: () {},
-        //     icon: const Icon(Icons.menu),
-        //     tooltip: 'Menu',
-        //   ),
-        // IconButton(
-        //   onPressed: () {},
-        //   icon: const Icon(Icons.login_sharp),
-        //   tooltip: 'Login',
-        // ),
-        // ],
+      ),
+      bottomNavigationBar: BottomNavigationBar(
+        items: const [
+          BottomNavigationBarItem(
+            label: 'Zurueck',
+            backgroundColor: Colors.white,
+            icon: Icon(
+              Icons.arrow_back,
+              color: Colors.white,
+            ),
+          ),
+          BottomNavigationBarItem(
+            backgroundColor: Colors.white,
+            label: 'AccountInf',
+            icon: Icon(
+              Icons.person,
+              color: Colors.white,
+            ),
+          ),
+        ],
+        backgroundColor: Colors.transparent,
       ),
       body: !_loading
           ? Form(
@@ -77,9 +64,9 @@ class _LoginPageState extends State<LoginPage> {
                 crossAxisAlignment: CrossAxisAlignment.center,
                 children: [
                   TextFormField(
-                    style: TextStyle(
-                      color: Theme.of(context).colorScheme.primary,
-                    ),
+                    // style: TextStyle(
+                    //   color: Theme.of(context).colorScheme.primary,
+                    // ),
                     controller: mailController,
                     decoration: const InputDecoration(
                       fillColor: Color.fromARGB(30, 255, 255, 255),
@@ -164,15 +151,7 @@ class _LoginPageState extends State<LoginPage> {
                 ],
               ),
             )
-          : Column(
-              mainAxisAlignment: MainAxisAlignment.center,
-              children: [
-                Image.asset(
-                  'lib/assets/logo_300x200.png',
-                  height: 300,
-                ),
-              ],
-            ),
+          : const LoadingWidget(),
     );
   }
 }
diff --git a/frontend/app/lib/widgets/loading_widget.dart b/frontend/app/lib/widgets/loading_widget.dart
new file mode 100644
index 0000000..567fbec
--- /dev/null
+++ b/frontend/app/lib/widgets/loading_widget.dart
@@ -0,0 +1,17 @@
+import 'package:flutter/material.dart';
+
+class LoadingWidget extends StatelessWidget {
+  const LoadingWidget({
+    super.key,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Center(
+      child: Image.asset(
+        'lib/assets/logo_300x200.png',
+        height: 300,
+      ),
+    );
+  }
+}

From 42dd9613d48e3a4d0db1256422c1382112468686 Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Fri, 27 Oct 2023 16:00:14 +0200
Subject: [PATCH 08/24] ch/update count_lines to exclude dirs

---
 Makefile | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 718f525..8f8e927 100644
--- a/Makefile
+++ b/Makefile
@@ -106,6 +106,6 @@ evans:
 	evans --host localhost --port 9090 --package pb -r repl
 
 count_lines:
-	cloc --exclude-dir=.history,.git .
+	cloc --exclude-dir=.history,.git,.idea,.dart_tool,build,ios,android,linux,macos,web,windows .
 
 .PHONY: reset_docker backend_build rebuild backend backend dev network postgres migratenew migrateup migratedown createdb dropdb sqlc sqlcinit test coverage server mock proto evans count_lines
\ No newline at end of file

From 6aeda6ea3466bd251d8d691659678be34cc3ccdf Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Fri, 27 Oct 2023 23:02:28 +0200
Subject: [PATCH 09/24] ft/adds landing page and refactors navigation

---
 .../JosefinSans-Italic-VariableFont_wght.ttf  | Bin 0 -> 125560 bytes
 .../fonts/JosefinSans-VariableFont_wght.ttf   | Bin 0 -> 117720 bytes
 frontend/app/lib/main.dart                    |   5 +-
 frontend/app/lib/pages/home_page.dart         | 154 +++++++++++++
 frontend/app/lib/pages/login_page.dart        | 216 ++++++++----------
 frontend/app/lib/pages/pages.dart             |   1 +
 frontend/app/lib/pages/start_page.dart        |  87 +++++++
 frontend/app/pubspec.yaml                     |   8 +-
 8 files changed, 345 insertions(+), 126 deletions(-)
 create mode 100644 frontend/app/lib/assets/fonts/JosefinSans-Italic-VariableFont_wght.ttf
 create mode 100644 frontend/app/lib/assets/fonts/JosefinSans-VariableFont_wght.ttf
 create mode 100644 frontend/app/lib/pages/home_page.dart
 create mode 100644 frontend/app/lib/pages/pages.dart
 create mode 100644 frontend/app/lib/pages/start_page.dart

diff --git a/frontend/app/lib/assets/fonts/JosefinSans-Italic-VariableFont_wght.ttf b/frontend/app/lib/assets/fonts/JosefinSans-Italic-VariableFont_wght.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..d2d2dd65dce900f6a4bbab7efeb0c0e5069ebfcd
GIT binary patch
literal 125560
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
KWAi1<tN#xqoUt|l

literal 0
HcmV?d00001

diff --git a/frontend/app/lib/assets/fonts/JosefinSans-VariableFont_wght.ttf b/frontend/app/lib/assets/fonts/JosefinSans-VariableFont_wght.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..00ea1e7d28e3bc88480b96ef14cb351b118546bf
GIT binary patch
literal 117720
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
O`Ivk>vjmZ@g!~`)FG`&N

literal 0
HcmV?d00001

diff --git a/frontend/app/lib/main.dart b/frontend/app/lib/main.dart
index 537dffe..2ef1cba 100644
--- a/frontend/app/lib/main.dart
+++ b/frontend/app/lib/main.dart
@@ -1,3 +1,4 @@
+import 'package:app/pages/home_page.dart';
 import 'package:app/pages/login_page.dart';
 import 'package:app/widgets/background.dart';
 import 'package:flutter/material.dart';
@@ -42,7 +43,9 @@ void main() async {
             backgroundColor: Colors.black,
             foregroundColor: Colors.white,
           )),
-      home: const Background(child: LoginPage()),
+      home: const Background(
+        child: HomePage(),
+      ),
     ),
   );
 }
diff --git a/frontend/app/lib/pages/home_page.dart b/frontend/app/lib/pages/home_page.dart
new file mode 100644
index 0000000..1e23107
--- /dev/null
+++ b/frontend/app/lib/pages/home_page.dart
@@ -0,0 +1,154 @@
+import 'package:app/gapi/client.dart';
+import 'package:app/pages/login_page.dart';
+import 'package:app/pages/start_page.dart';
+import 'package:flutter/material.dart';
+import 'package:app/pages/pages.dart';
+
+Map<Pages, List<BottomNavigationBarItem>> bottomBarButtons = {
+  Pages.start: const [
+    BottomNavigationBarItem(
+      label: 'Zurueck',
+      backgroundColor: Colors.white,
+      icon: Icon(
+        Icons.arrow_back,
+        color: Colors.white,
+      ),
+    ),
+    BottomNavigationBarItem(
+      backgroundColor: Colors.white,
+      label: 'AccountInf',
+      icon: Icon(
+        Icons.person,
+        color: Colors.white,
+      ),
+    ),
+  ],
+  Pages.persons: const [
+    BottomNavigationBarItem(
+      label: 'Zurueck',
+      backgroundColor: Colors.white,
+      icon: Icon(
+        Icons.arrow_back,
+        color: Colors.white,
+      ),
+    ),
+    BottomNavigationBarItem(
+      backgroundColor: Colors.white,
+      label: 'AccountInf',
+      icon: Icon(
+        Icons.person,
+        color: Colors.white,
+      ),
+    ),
+  ],
+  Pages.about: const [
+    BottomNavigationBarItem(
+      label: 'Zurueck',
+      backgroundColor: Colors.white,
+      icon: Icon(
+        Icons.arrow_back,
+        color: Colors.white,
+      ),
+    ),
+    BottomNavigationBarItem(
+      backgroundColor: Colors.white,
+      label: 'AccountInf',
+      icon: Icon(
+        Icons.person,
+        color: Colors.white,
+      ),
+    ),
+  ],
+  Pages.login: const [
+    BottomNavigationBarItem(
+      label: 'Zurueck',
+      backgroundColor: Colors.white,
+      icon: Icon(
+        Icons.arrow_back,
+        color: Colors.white,
+      ),
+    ),
+    BottomNavigationBarItem(
+      backgroundColor: Colors.white,
+      label: 'AccountInf',
+      icon: Icon(
+        Icons.person,
+        color: Colors.white,
+      ),
+    ),
+  ]
+};
+
+class HomePage extends StatefulWidget {
+  const HomePage({super.key});
+
+  @override
+  State<HomePage> createState() => _HomePageState();
+}
+
+class _HomePageState extends State<HomePage> {
+  bool _loading = false;
+
+  Pages _selectedPage = Pages.start;
+
+  Widget _selectPage(Pages page) {
+    switch (page) {
+      case Pages.login:
+        return const LoginPage();
+      default:
+        return StartPage(onChangePage: changePage);
+    }
+  }
+
+  Future<bool> _onWillPop() async {
+    changePage(Pages.start);
+    return false;
+  }
+
+  void changePage(Pages page) {
+    if (!Pages.values.contains(page)) {
+      page = _selectedPage;
+    }
+    setState(() {
+      _selectedPage = page;
+    });
+  }
+
+  void _setLoading(bool loading) {
+    setState(() {
+      _loading = loading;
+    });
+  }
+
+  final Client client = Client();
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: _selectedPage == 'start'
+          ? AppBar(
+              automaticallyImplyLeading: false,
+            )
+          : AppBar(
+              automaticallyImplyLeading: false,
+              flexibleSpace: Image.asset(
+                'lib/assets/logo_300x200.png',
+                height: 80,
+              ),
+            ),
+      bottomNavigationBar: BottomNavigationBar(
+        items: bottomBarButtons[_selectedPage]!.toList(),
+        backgroundColor: Colors.transparent,
+      ),
+      body: Container(
+        padding: const EdgeInsets.fromLTRB(16, 32, 16, 32),
+        child: Center(
+          child: WillPopScope(
+            child: _selectPage(_selectedPage),
+            onWillPop: () => _onWillPop(),
+          ),
+        ),
+      ),
+    );
+  }
+}
diff --git a/frontend/app/lib/pages/login_page.dart b/frontend/app/lib/pages/login_page.dart
index 89ddd00..b9239c8 100644
--- a/frontend/app/lib/pages/login_page.dart
+++ b/frontend/app/lib/pages/login_page.dart
@@ -27,131 +27,101 @@ class _LoginPageState extends State<LoginPage> {
 
   @override
   Widget build(BuildContext context) {
-    return Scaffold(
-      appBar: AppBar(
-        automaticallyImplyLeading: false,
-        flexibleSpace: Image.asset(
-          'lib/assets/logo_300x200.png',
-          height: 80,
-        ),
-      ),
-      bottomNavigationBar: BottomNavigationBar(
-        items: const [
-          BottomNavigationBarItem(
-            label: 'Zurueck',
-            backgroundColor: Colors.white,
-            icon: Icon(
-              Icons.arrow_back,
-              color: Colors.white,
-            ),
-          ),
-          BottomNavigationBarItem(
-            backgroundColor: Colors.white,
-            label: 'AccountInf',
-            icon: Icon(
-              Icons.person,
-              color: Colors.white,
-            ),
-          ),
-        ],
-        backgroundColor: Colors.transparent,
-      ),
-      body: !_loading
-          ? Form(
-              key: _formKey,
-              child: Column(
-                mainAxisAlignment: MainAxisAlignment.center,
-                crossAxisAlignment: CrossAxisAlignment.center,
-                children: [
-                  TextFormField(
-                    // style: TextStyle(
-                    //   color: Theme.of(context).colorScheme.primary,
-                    // ),
-                    controller: mailController,
-                    decoration: const InputDecoration(
-                      fillColor: Color.fromARGB(30, 255, 255, 255),
-                      filled: true,
-                      hintStyle: TextStyle(
-                        color: Colors.white38,
-                      ),
-                      hintText: 'E-Mail Adresse',
+    return !_loading
+        ? Form(
+            key: _formKey,
+            child: Column(
+              mainAxisAlignment: MainAxisAlignment.center,
+              crossAxisAlignment: CrossAxisAlignment.center,
+              children: [
+                TextFormField(
+                  // style: TextStyle(
+                  //   color: Theme.of(context).colorScheme.primary,
+                  // ),
+                  controller: mailController,
+                  decoration: const InputDecoration(
+                    fillColor: Color.fromARGB(30, 255, 255, 255),
+                    filled: true,
+                    hintStyle: TextStyle(
+                      color: Colors.white38,
                     ),
-                    keyboardType: TextInputType.emailAddress,
-                    validator: (value) {
-                      if (value == null || value.isEmpty) {
-                        return 'Bitte eine gültige E-Mail Adresse eingeben';
-                      }
-                      return null;
-                    },
+                    hintText: 'E-Mail Adresse',
                   ),
-                  TextFormField(
-                    style: const TextStyle(
-                      color: Colors.white,
-                    ),
-                    controller: passwordController,
-                    decoration: const InputDecoration(
-                      fillColor: Color.fromARGB(30, 255, 255, 255),
-                      filled: true,
-                      hintStyle: TextStyle(
-                        color: Colors.white38,
-                      ),
-                      hintText: 'Passwort',
-                    ),
-                    keyboardType: TextInputType.visiblePassword,
-                    obscureText: true,
-                    validator: (value) {
-                      if (value == null || value.isEmpty) {
-                        return 'Bitte geben Sie Ihr Passwort ein';
-                      }
-                      return null;
-                    },
+                  keyboardType: TextInputType.emailAddress,
+                  validator: (value) {
+                    if (value == null || value.isEmpty) {
+                      return 'Bitte eine gültige E-Mail Adresse eingeben';
+                    }
+                    return null;
+                  },
+                ),
+                TextFormField(
+                  style: const TextStyle(
+                    color: Colors.white,
                   ),
-                  ElevatedButton(
-                      onPressed: () {
-                        if (_formKey.currentState!.validate()) {
-                          // final navigator = Navigator.of(context);
-                          _setLoading(true);
-                          client
-                              .login(
-                            email: mailController.text,
-                            password: passwordController.text,
-                            onError: () {
-                              _setLoading(false);
-                              ScaffoldMessenger.of(context)
-                                  .showSnackBar(const SnackBar(
-                                content: Text('Login fehlgeschlagen'),
-                              ));
-                            },
-                            onSuccess: () {
-                              // _setLoading(false);
-                              ScaffoldMessenger.of(context)
-                                  .showSnackBar(const SnackBar(
-                                content: Text('Login erfolgreich'),
-                              ));
-                            },
-                          )
-                              .then(
-                            (r) {
-                              if (r.accessToken != '') {
-                                Navigator.pushAndRemoveUntil(
-                                    context,
-                                    MaterialPageRoute(
-                                      builder: (ctx) => DashboardPage(
-                                        client: client,
-                                      ),
-                                    ),
-                                    (route) => false);
-                              }
-                              // _setLoading(false);
-                            },
-                          );
-                        }
-                      },
-                      child: const Icon(Icons.arrow_forward))
-                ],
-              ),
-            )
-          : const LoadingWidget(),
-    );
+                  controller: passwordController,
+                  decoration: const InputDecoration(
+                    fillColor: Color.fromARGB(30, 255, 255, 255),
+                    filled: true,
+                    hintStyle: TextStyle(
+                      color: Colors.white38,
+                    ),
+                    hintText: 'Passwort',
+                  ),
+                  keyboardType: TextInputType.visiblePassword,
+                  obscureText: true,
+                  validator: (value) {
+                    if (value == null || value.isEmpty) {
+                      return 'Bitte geben Sie Ihr Passwort ein';
+                    }
+                    return null;
+                  },
+                ),
+                ElevatedButton(
+                    onPressed: () {
+                      if (_formKey.currentState!.validate()) {
+                        // final navigator = Navigator.of(context);
+                        _setLoading(true);
+                        client
+                            .login(
+                          email: mailController.text,
+                          password: passwordController.text,
+                          onError: () {
+                            _setLoading(false);
+                            ScaffoldMessenger.of(context)
+                                .showSnackBar(const SnackBar(
+                              content: Text('Login fehlgeschlagen'),
+                            ));
+                          },
+                          onSuccess: () {
+                            // _setLoading(false);
+                            ScaffoldMessenger.of(context)
+                                .showSnackBar(const SnackBar(
+                              content: Text('Login erfolgreich'),
+                            ));
+                          },
+                        )
+                            .then(
+                          (r) {
+                            if (r.accessToken != '') {
+                              Navigator.push(
+                                context,
+                                MaterialPageRoute(
+                                  builder: (ctx) => DashboardPage(
+                                    client: client,
+                                  ),
+                                ),
+                              );
+                            }
+                            // _setLoading(false);
+                          },
+                        );
+                      }
+                    },
+                    child: const Icon(Icons.arrow_forward))
+              ],
+            ),
+          )
+        : const LoadingWidget();
   }
 }
diff --git a/frontend/app/lib/pages/pages.dart b/frontend/app/lib/pages/pages.dart
new file mode 100644
index 0000000..b8f802a
--- /dev/null
+++ b/frontend/app/lib/pages/pages.dart
@@ -0,0 +1 @@
+enum Pages { start, login, about, persons }
diff --git a/frontend/app/lib/pages/start_page.dart b/frontend/app/lib/pages/start_page.dart
new file mode 100644
index 0000000..0896168
--- /dev/null
+++ b/frontend/app/lib/pages/start_page.dart
@@ -0,0 +1,87 @@
+import 'package:app/pages/pages.dart';
+import 'package:flutter/material.dart';
+import 'dart:core';
+
+class StartPage extends StatelessWidget {
+  StartPage({
+    super.key,
+    required this.onChangePage,
+  });
+
+  void Function(Pages page) onChangePage;
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      mainAxisAlignment: MainAxisAlignment.center,
+      children: [
+        const Image(
+          image: AssetImage(
+            'lib/assets/logo_300x200.png',
+          ),
+        ),
+        // Text(
+        //   'Peace of Mind \nin the\nAfterlife',
+        //   textAlign: TextAlign.center,
+        //   style: TextStyle(
+        //     fontFamily: 'JosefinSans',
+        //     height: 1.7,
+        //     letterSpacing: 8,
+        //     wordSpacing: 2,
+        //     fontWeight: FontWeight.bold,
+        //     fontSize: 32,
+        //     color: Colors.white,
+        //     decoration: TextDecoration.none,
+        //     decorationColor: Colors.white,
+        //   ),
+        // ),
+        const SizedBox(
+          height: 40,
+        ),
+        Text(
+          'Digitale Spuren auf Knopfdruck entfernen'.toUpperCase(),
+          textAlign: TextAlign.center,
+          style: const TextStyle(
+            fontFamily: 'sans-serif',
+            fontSize: 24,
+            height: 1.6,
+            fontWeight: FontWeight.normal,
+            letterSpacing: 6,
+          ),
+        ),
+        const Spacer(),
+        Row(
+          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+          crossAxisAlignment: CrossAxisAlignment.center,
+          children: [
+            ElevatedButton.icon(
+              label: const Text('Login'),
+              onPressed: () {
+                onChangePage(Pages.login);
+              },
+              icon: const Icon(
+                Icons.login,
+                semanticLabel: 'Login',
+                size: 16,
+              ),
+            ),
+            ElevatedButton.icon(
+              label: const Text('Registrieren'),
+              onPressed: () {},
+              icon: const Icon(
+                Icons.person_add,
+                semanticLabel: 'Register',
+                size: 16,
+              ),
+            ),
+          ],
+        ),
+        // const SizedBox(
+        //   height: 32,
+        // ),
+
+        // const Text('data'),
+      ],
+    );
+  }
+}
diff --git a/frontend/app/pubspec.yaml b/frontend/app/pubspec.yaml
index 6b33b3f..07e48bb 100644
--- a/frontend/app/pubspec.yaml
+++ b/frontend/app/pubspec.yaml
@@ -81,8 +81,12 @@ flutter:
   # "family" key with the font family name, and a "fonts" key with a
   # list giving the asset and other descriptors for the font. For
   # example:
-  # fonts:
-  #   - family: Schyler
+  fonts:
+    - family: JosefinSans
+      fonts:
+        - asset: lib/assets/fonts/JosefinSans-Italic-VariableFont_wght.ttf
+          style: italic
+        - asset: lib/assets/fonts/JosefinSans-VariableFont_wght.ttf
   #     fonts:
   #       - asset: fonts/Schyler-Regular.ttf
   #       - asset: fonts/Schyler-Italic.ttf

From 5bd03eab7ca210d09def4adf5248af53ee9e3c25 Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Sat, 28 Oct 2023 23:27:51 +0200
Subject: [PATCH 10/24] ft/adds drawer and refactors navigation

---
 frontend/app/lib/gapi/client.dart          |   8 +-
 frontend/app/lib/main.dart                 |   6 +-
 frontend/app/lib/pages/dashboard_page.dart | 126 +++----
 frontend/app/lib/pages/home_page.dart      |  14 +-
 frontend/app/lib/pages/login_page.dart     | 377 ++++++++++++++++-----
 frontend/app/lib/pages/pages.dart          |   2 +-
 frontend/app/lib/pages/start_page.dart     | 289 ++++++++++++----
 7 files changed, 577 insertions(+), 245 deletions(-)

diff --git a/frontend/app/lib/gapi/client.dart b/frontend/app/lib/gapi/client.dart
index a27f966..e4e225e 100644
--- a/frontend/app/lib/gapi/client.dart
+++ b/frontend/app/lib/gapi/client.dart
@@ -5,7 +5,7 @@ import 'package:app/pb/rpc_login.pb.dart';
 import 'package:app/pb/service_df.pbgrpc.dart';
 import 'package:grpc/grpc.dart';
 
-class Client {
+class GClient {
   String baseUrl = 'localhost';
   int port = 9090;
 
@@ -39,7 +39,7 @@ class Client {
   Future<LoginResponse> login(
       {required String email,
       required String password,
-      required Function onError,
+      required Function({GrpcError? error}) onError,
       required Function onSuccess}) async {
     LoginResponse response = LoginResponse();
     try {
@@ -56,9 +56,9 @@ class Client {
     } on GrpcError catch (e) {
       print('caught error: ${e.message}');
       metadata['Authorization'] = '';
-      onError();
+      onError(error: e);
     } catch (e) {
-      print('caught error: ${e}');
+      print('caught error: $e');
       metadata['Authorization'] = '';
       onError();
     }
diff --git a/frontend/app/lib/main.dart b/frontend/app/lib/main.dart
index 2ef1cba..4a983e1 100644
--- a/frontend/app/lib/main.dart
+++ b/frontend/app/lib/main.dart
@@ -1,5 +1,5 @@
 import 'package:app/pages/home_page.dart';
-import 'package:app/pages/login_page.dart';
+import 'package:app/pages/start_page.dart';
 import 'package:app/widgets/background.dart';
 import 'package:flutter/material.dart';
 
@@ -43,8 +43,8 @@ void main() async {
             backgroundColor: Colors.black,
             foregroundColor: Colors.white,
           )),
-      home: const Background(
-        child: HomePage(),
+      home: Background(
+        child: StartPage(),
       ),
     ),
   );
diff --git a/frontend/app/lib/pages/dashboard_page.dart b/frontend/app/lib/pages/dashboard_page.dart
index 84bd1d4..012d74a 100644
--- a/frontend/app/lib/pages/dashboard_page.dart
+++ b/frontend/app/lib/pages/dashboard_page.dart
@@ -5,10 +5,31 @@ import 'package:app/widgets/background.dart';
 import 'package:app/widgets/loading_widget.dart';
 import 'package:flutter/material.dart';
 
+GlobalKey<ScaffoldState> scaffolKey = GlobalKey<ScaffoldState>();
+
+List<BottomNavigationBarItem> bottomBarButtons = const [
+  BottomNavigationBarItem(
+    label: 'Zurueck',
+    backgroundColor: Colors.white,
+    icon: Icon(
+      Icons.arrow_back,
+      color: Colors.white,
+    ),
+  ),
+  BottomNavigationBarItem(
+    backgroundColor: Colors.white,
+    label: 'AccountInf',
+    icon: Icon(
+      Icons.person,
+      color: Colors.white,
+    ),
+  ),
+];
+
 class DashboardPage extends StatefulWidget {
   DashboardPage({super.key, required this.client});
 
-  final Client client;
+  final GClient client;
 
   @override
   State<DashboardPage> createState() => _DashboardPageState();
@@ -50,83 +71,40 @@ class _DashboardPageState extends State<DashboardPage> {
 
   @override
   Widget build(BuildContext context) {
-    print(widget.client.accessToken);
-    return Scaffold(
-      bottomNavigationBar: BottomNavigationBar(
-        items: const [
-          BottomNavigationBarItem(
-            label: '',
-            backgroundColor: Colors.white,
-            icon: Icon(
-              Icons.arrow_back,
-              color: Colors.white,
-            ),
+    return Background(
+      child: Scaffold(
+        key: scaffolKey,
+        appBar: AppBar(
+          automaticallyImplyLeading: false,
+          flexibleSpace: Image.asset(
+            'lib/assets/logo_300x200.png',
+            height: 80,
           ),
-          BottomNavigationBarItem(
-            backgroundColor: Colors.white,
-            label: '',
-            icon: Icon(
-              Icons.person,
-              color: Colors.white,
-            ),
-          ),
-          BottomNavigationBarItem(
-            backgroundColor: Colors.white,
-            label: '',
-            icon: Icon(
-              Icons.group,
-              color: Colors.white,
-            ),
-          ),
-          BottomNavigationBarItem(
-            backgroundColor: Colors.white,
-            label: '',
-            icon: Icon(
-              Icons.file_copy,
-              color: Colors.white,
-            ),
-          ),
-        ],
-        backgroundColor: Colors.transparent,
-      ),
-      appBar: AppBar(
-        automaticallyImplyLeading: false,
-        flexibleSpace: Image.asset(
-          'lib/assets/logo_300x200.png',
-          height: 80,
         ),
-        // actions: [
-        //   IconButton(
-        //     onPressed: () {},
-        //     icon: const Icon(Icons.menu),
-        //     tooltip: 'Menu',
-        //   ),
-        // IconButton(
-        //   onPressed: () {},
-        //   icon: const Icon(Icons.login_sharp),
-        //   tooltip: 'Login',
-        // ),
-        // ],
-      ),
-      body: !_loading
-          ? Background(
-              child: Center(
-                child: Column(
-                  children: [
-                    const SizedBox(
-                      height: 48,
-                    ),
-                    Text(
-                      'Willkommen ${accountInfo.firstname} ${accountInfo.lastname}!',
-                      style: const TextStyle(
-                        fontSize: 24,
+        bottomNavigationBar: BottomNavigationBar(
+          items: bottomBarButtons,
+          backgroundColor: Colors.black,
+        ),
+        body: !_loading
+            ? Background(
+                child: Center(
+                  child: Column(
+                    children: [
+                      const SizedBox(
+                        height: 48,
                       ),
-                    ),
-                  ],
+                      Text(
+                        'Willkommen ${accountInfo.firstname} ${accountInfo.lastname}!',
+                        style: const TextStyle(
+                          fontSize: 24,
+                        ),
+                      ),
+                    ],
+                  ),
                 ),
-              ),
-            )
-          : const LoadingWidget(),
+              )
+            : const LoadingWidget(),
+      ),
     );
   }
 }
diff --git a/frontend/app/lib/pages/home_page.dart b/frontend/app/lib/pages/home_page.dart
index 1e23107..6b544e8 100644
--- a/frontend/app/lib/pages/home_page.dart
+++ b/frontend/app/lib/pages/home_page.dart
@@ -94,9 +94,13 @@ class _HomePageState extends State<HomePage> {
   Widget _selectPage(Pages page) {
     switch (page) {
       case Pages.login:
-        return const LoginPage();
+        return LoginPage(
+            // onChangePage: changePage,
+            );
       default:
-        return StartPage(onChangePage: changePage);
+        return StartPage(
+            // onChangePage: changePage,
+            );
     }
   }
 
@@ -120,12 +124,12 @@ class _HomePageState extends State<HomePage> {
     });
   }
 
-  final Client client = Client();
+  final GClient client = GClient();
 
   @override
   Widget build(BuildContext context) {
     return Scaffold(
-      appBar: _selectedPage == 'start'
+      appBar: _selectedPage == Pages.start
           ? AppBar(
               automaticallyImplyLeading: false,
             )
@@ -138,7 +142,7 @@ class _HomePageState extends State<HomePage> {
             ),
       bottomNavigationBar: BottomNavigationBar(
         items: bottomBarButtons[_selectedPage]!.toList(),
-        backgroundColor: Colors.transparent,
+        backgroundColor: Colors.black,
       ),
       body: Container(
         padding: const EdgeInsets.fromLTRB(16, 32, 16, 32),
diff --git a/frontend/app/lib/pages/login_page.dart b/frontend/app/lib/pages/login_page.dart
index b9239c8..9daad16 100644
--- a/frontend/app/lib/pages/login_page.dart
+++ b/frontend/app/lib/pages/login_page.dart
@@ -1,10 +1,41 @@
 import 'package:app/gapi/client.dart';
-import 'package:app/pages/dashboard_page.dart';
+import 'package:app/pages/start_page.dart';
+import 'package:app/widgets/background.dart';
 import 'package:app/widgets/loading_widget.dart';
 import 'package:flutter/material.dart';
+import 'package:grpc/grpc.dart';
+
+GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
+
+List<BottomNavigationBarItem> bottomBarButtons = [
+  const BottomNavigationBarItem(
+    label: 'back',
+    backgroundColor: Colors.white,
+    icon: Icon(
+      Icons.arrow_back,
+      color: Colors.white,
+    ),
+  ),
+  BottomNavigationBarItem(
+    backgroundColor: Colors.white,
+    label: 'Menu',
+    icon: IconButton(
+      onPressed: () => scaffoldKey.currentState!.openDrawer(),
+      icon: const Icon(
+        Icons.menu,
+        color: Colors.white,
+      ),
+    ),
+  ),
+];
 
 class LoginPage extends StatefulWidget {
-  const LoginPage({super.key});
+  LoginPage({
+    super.key,
+    // required this.onChangePage,
+  });
+
+  // void Function(Pages page) onChangePage;
 
   @override
   State<LoginPage> createState() => _LoginPageState();
@@ -13,13 +44,22 @@ class LoginPage extends StatefulWidget {
 class _LoginPageState extends State<LoginPage> {
   bool _loading = false;
 
+  List<BottomNavigationBarItem> _selectedBottomBarButtons = bottomBarButtons;
+
+  void _bottomBarAction(int index) {
+    switch (_selectedBottomBarButtons[index].label?.toLowerCase()) {
+      case 'back':
+        Navigator.of(context).pop();
+    }
+  }
+
   void _setLoading(bool loading) {
     setState(() {
       _loading = loading;
     });
   }
 
-  final Client client = Client();
+  final GClient client = GClient();
 
   final _formKey = GlobalKey<FormState>();
   final mailController = TextEditingController();
@@ -27,101 +67,258 @@ class _LoginPageState extends State<LoginPage> {
 
   @override
   Widget build(BuildContext context) {
-    return !_loading
-        ? Form(
-            key: _formKey,
+    return Background(
+      child: Scaffold(
+        key: scaffoldKey,
+        appBar: AppBar(
+          automaticallyImplyLeading: false,
+          // flexibleSpace: Image.asset(
+          //   'lib/assets/logo_300x200.png',
+          //   height: 80,
+          // ),
+        ),
+        bottomNavigationBar: BottomNavigationBar(
+          items: bottomBarButtons,
+          backgroundColor: Colors.black,
+          fixedColor: Colors.black,
+          onTap: (value) => _bottomBarAction(value),
+        ),
+        drawer: Drawer(
+          backgroundColor: Colors.black,
+          child: Padding(
+            padding: const EdgeInsets.all(40.0),
             child: Column(
               mainAxisAlignment: MainAxisAlignment.center,
-              crossAxisAlignment: CrossAxisAlignment.center,
               children: [
-                TextFormField(
-                  // style: TextStyle(
-                  //   color: Theme.of(context).colorScheme.primary,
-                  // ),
-                  controller: mailController,
-                  decoration: const InputDecoration(
-                    fillColor: Color.fromARGB(30, 255, 255, 255),
-                    filled: true,
-                    hintStyle: TextStyle(
-                      color: Colors.white38,
-                    ),
-                    hintText: 'E-Mail Adresse',
-                  ),
-                  keyboardType: TextInputType.emailAddress,
-                  validator: (value) {
-                    if (value == null || value.isEmpty) {
-                      return 'Bitte eine gültige E-Mail Adresse eingeben';
-                    }
-                    return null;
+                const Spacer(),
+                TextButton(
+                  onPressed: () {
+                    scaffoldKey.currentState!.closeDrawer();
                   },
+                  child: const Row(
+                    children: [
+                      Text(
+                        'About',
+                        style: TextStyle(fontSize: 20),
+                      ),
+                      Spacer(),
+                      Icon(
+                        Icons.question_answer,
+                        color: Colors.white,
+                      ),
+                    ],
+                  ),
                 ),
-                TextFormField(
-                  style: const TextStyle(
-                    color: Colors.white,
-                  ),
-                  controller: passwordController,
-                  decoration: const InputDecoration(
-                    fillColor: Color.fromARGB(30, 255, 255, 255),
-                    filled: true,
-                    hintStyle: TextStyle(
-                      color: Colors.white38,
-                    ),
-                    hintText: 'Passwort',
-                  ),
-                  keyboardType: TextInputType.visiblePassword,
-                  obscureText: true,
-                  validator: (value) {
-                    if (value == null || value.isEmpty) {
-                      return 'Bitte geben Sie Ihr Passwort ein';
-                    }
-                    return null;
+                TextButton(
+                  onPressed: () {
+                    scaffoldKey.currentState!.closeDrawer();
                   },
+                  child: const Row(
+                    children: [
+                      Text(
+                        'Datenschutz',
+                        style: TextStyle(fontSize: 20),
+                      ),
+                      Spacer(),
+                      Icon(
+                        Icons.privacy_tip,
+                        color: Colors.white,
+                      ),
+                    ],
+                  ),
                 ),
-                ElevatedButton(
-                    onPressed: () {
-                      if (_formKey.currentState!.validate()) {
-                        // final navigator = Navigator.of(context);
-                        _setLoading(true);
-                        client
-                            .login(
-                          email: mailController.text,
-                          password: passwordController.text,
-                          onError: () {
-                            _setLoading(false);
-                            ScaffoldMessenger.of(context)
-                                .showSnackBar(const SnackBar(
-                              content: Text('Login fehlgeschlagen'),
-                            ));
-                          },
-                          onSuccess: () {
-                            // _setLoading(false);
-                            ScaffoldMessenger.of(context)
-                                .showSnackBar(const SnackBar(
-                              content: Text('Login erfolgreich'),
-                            ));
-                          },
-                        )
-                            .then(
-                          (r) {
-                            if (r.accessToken != '') {
-                              Navigator.push(
-                                context,
-                                MaterialPageRoute(
-                                  builder: (ctx) => DashboardPage(
-                                    client: client,
-                                  ),
-                                ),
-                              );
-                            }
-                            // _setLoading(false);
-                          },
-                        );
-                      }
-                    },
-                    child: const Icon(Icons.arrow_forward))
+                TextButton(
+                  onPressed: () {
+                    scaffoldKey.currentState!.closeDrawer();
+                  },
+                  child: const Row(
+                    children: [
+                      Text(
+                        'Impressum',
+                        style: TextStyle(fontSize: 20),
+                      ),
+                      Spacer(),
+                      Icon(
+                        Icons.apartment,
+                        color: Colors.white,
+                      ),
+                    ],
+                  ),
+                ),
+                const SizedBox(
+                  height: 250,
+                )
               ],
             ),
-          )
-        : const LoadingWidget();
+          ),
+        ),
+        body: !_loading
+            ? Form(
+                key: _formKey,
+                child: Padding(
+                  padding: const EdgeInsets.fromLTRB(16, 100, 16, 16),
+                  child: SingleChildScrollView(
+                    child: Column(
+                      // mainAxisAlignment: MainAxisAlignment.spaceAround,
+                      crossAxisAlignment: CrossAxisAlignment.center,
+                      children: [
+                        const Image(
+                          width: 180,
+                          image: AssetImage(
+                            'lib/assets/logo_300x200.png',
+                          ),
+                        ),
+                        const SizedBox(
+                          height: 30,
+                        ),
+                        const Text(
+                          'Login',
+                          style: TextStyle(
+                            fontFamily: 'sans-serif',
+                            fontSize: 24,
+                            height: 1.6,
+                            fontWeight: FontWeight.normal,
+                            letterSpacing: 6,
+                          ),
+                        ),
+                        const SizedBox(
+                          height: 20,
+                        ),
+                        TextFormField(
+                          // style: TextStyle(
+                          //   color: Theme.of(context).colorScheme.primary,
+                          // ),
+                          controller: mailController,
+                          decoration: const InputDecoration(
+                            fillColor: Color.fromARGB(30, 255, 255, 255),
+                            filled: true,
+                            hintStyle: TextStyle(
+                              color: Colors.white38,
+                            ),
+                            hintText: 'E-Mail Adresse',
+                          ),
+                          keyboardType: TextInputType.emailAddress,
+                          validator: (value) {
+                            if (value == null || value.isEmpty) {
+                              return 'Bitte eine gültige E-Mail Adresse eingeben';
+                            }
+                            return null;
+                          },
+                        ),
+                        TextFormField(
+                          style: const TextStyle(
+                            color: Colors.white,
+                          ),
+                          controller: passwordController,
+                          decoration: const InputDecoration(
+                            fillColor: Color.fromARGB(30, 255, 255, 255),
+                            filled: true,
+                            hintStyle: TextStyle(
+                              color: Colors.white38,
+                            ),
+                            hintText: 'Passwort',
+                          ),
+                          keyboardType: TextInputType.visiblePassword,
+                          obscureText: true,
+                          validator: (value) {
+                            if (value == null || value.isEmpty) {
+                              return 'Bitte geben Sie Ihr Passwort ein';
+                            }
+                            return null;
+                          },
+                        ),
+                        SizedBox(
+                          height: 15,
+                        ),
+                        ElevatedButton(
+                            onPressed: () {
+                              if (_formKey.currentState!.validate()) {
+                                // final navigator = Navigator.of(context);
+                                _setLoading(true);
+                                client
+                                    .login(
+                                  email: mailController.text,
+                                  password: passwordController.text,
+                                  onError: ({GrpcError? error}) {
+                                    _setLoading(false);
+                                    ScaffoldMessenger.of(context)
+                                        .showSnackBar(SnackBar(
+                                      content: const Text(
+                                        'Login fehlgeschlagen',
+                                      ),
+                                      action: SnackBarAction(
+                                          textColor: Colors.grey,
+                                          label: 'Details',
+                                          onPressed: () {
+                                            showDialog(
+                                              context: context,
+                                              builder: (context) {
+                                                return AlertDialog(
+                                                  content: error != null
+                                                      ? Text(
+                                                          'Fehler: ${error.message}',
+                                                          textAlign:
+                                                              TextAlign.center,
+                                                          style:
+                                                              const TextStyle(
+                                                                  color: Colors
+                                                                      .black),
+                                                        )
+                                                      : const Text(
+                                                          'Interner Fehler',
+                                                          textAlign:
+                                                              TextAlign.center,
+                                                          style: TextStyle(
+                                                              color:
+                                                                  Colors.black),
+                                                        ),
+                                                  icon: const Icon(
+                                                    Icons.error,
+                                                    color: Colors.black,
+                                                  ),
+                                                );
+                                              },
+                                            );
+                                          }),
+                                    ));
+                                  },
+                                  onSuccess: () {
+                                    // _setLoading(false);
+                                    ScaffoldMessenger.of(context)
+                                        .showSnackBar(const SnackBar(
+                                      content: Text('Login erfolgreich'),
+                                    ));
+                                  },
+                                )
+                                    .then(
+                                  (r) {
+                                    if (r.accessToken != '') {
+                                      Navigator.pushAndRemoveUntil(
+                                        context,
+                                        MaterialPageRoute(
+                                          builder: (ctx) => StartPage(
+                                            client: client,
+                                          ),
+                                        ),
+                                        (ctx) => false,
+                                      );
+                                      // widget.onChangePage(
+                                      //   Pages.dashboard,
+                                      // );
+                                    }
+                                    // _setLoading(false);
+                                  },
+                                );
+                              }
+                            },
+                            child: const Icon(Icons.login))
+                      ],
+                    ),
+                  ),
+                ),
+              )
+            : const LoadingWidget(),
+      ),
+    );
   }
 }
diff --git a/frontend/app/lib/pages/pages.dart b/frontend/app/lib/pages/pages.dart
index b8f802a..6db3efe 100644
--- a/frontend/app/lib/pages/pages.dart
+++ b/frontend/app/lib/pages/pages.dart
@@ -1 +1 @@
-enum Pages { start, login, about, persons }
+enum Pages { start, login, about, persons, dashboard }
diff --git a/frontend/app/lib/pages/start_page.dart b/frontend/app/lib/pages/start_page.dart
index 0896168..c1a6d59 100644
--- a/frontend/app/lib/pages/start_page.dart
+++ b/frontend/app/lib/pages/start_page.dart
@@ -1,87 +1,240 @@
-import 'package:app/pages/pages.dart';
+import 'package:app/gapi/client.dart';
+import 'package:app/pages/login_page.dart';
+import 'package:app/widgets/background.dart';
 import 'package:flutter/material.dart';
 import 'dart:core';
 
-class StartPage extends StatelessWidget {
+GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
+
+List<BottomNavigationBarItem> bottomBarButtons = [
+  const BottomNavigationBarItem(
+    label: 'register',
+    backgroundColor: Colors.white,
+    icon: Column(
+      children: [
+        Icon(
+          Icons.person_add,
+          color: Colors.white,
+        ),
+        Text(
+          'Registrieren',
+          style: TextStyle(
+            color: Colors.white,
+            fontSize: 16,
+          ),
+        )
+      ],
+    ),
+  ),
+  const BottomNavigationBarItem(
+    label: 'login',
+    backgroundColor: Colors.white,
+    icon: Column(
+      children: [
+        Icon(
+          Icons.login,
+          color: Colors.white,
+        ),
+        Text(
+          'Login',
+          style: TextStyle(
+            color: Colors.white,
+            fontSize: 16,
+          ),
+        )
+      ],
+    ),
+  ),
+  BottomNavigationBarItem(
+    backgroundColor: Colors.white,
+    label: 'Menu',
+    icon: IconButton(
+      onPressed: () => scaffoldKey.currentState!.openDrawer(),
+      icon: const Icon(
+        Icons.menu,
+        color: Colors.white,
+      ),
+    ),
+  ),
+];
+
+class StartPage extends StatefulWidget {
   StartPage({
     super.key,
-    required this.onChangePage,
+    this.client,
   });
 
-  void Function(Pages page) onChangePage;
+  final GClient? client;
+
+  @override
+  State<StartPage> createState() => _StartPageState();
+}
+
+class _StartPageState extends State<StartPage> {
+  List<BottomNavigationBarItem> _selectedBottomBarButtons = bottomBarButtons;
+
+  void _bottomBarAction(int index) {
+    switch (_selectedBottomBarButtons[index].label?.toLowerCase()) {
+      case 'login':
+        Navigator.of(context)
+            .push(MaterialPageRoute(builder: (context) => LoginPage()));
+    }
+  }
 
   @override
   Widget build(BuildContext context) {
-    return Column(
-      mainAxisAlignment: MainAxisAlignment.center,
-      children: [
-        const Image(
-          image: AssetImage(
-            'lib/assets/logo_300x200.png',
+    return Background(
+      child: Scaffold(
+        key: scaffoldKey,
+        appBar: AppBar(
+          automaticallyImplyLeading: false,
+          // flexibleSpace: Image.asset(
+          //   'lib/assets/logo_300x200.png',
+          //   height: 80,
+          // ),
+        ),
+        drawer: Drawer(
+          backgroundColor: Colors.black,
+          child: Padding(
+            padding: const EdgeInsets.all(40.0),
+            child: Column(
+              mainAxisAlignment: MainAxisAlignment.center,
+              children: [
+                const Spacer(),
+                TextButton(
+                  onPressed: () {
+                    scaffoldKey.currentState!.closeDrawer();
+                  },
+                  child: const Row(
+                    children: [
+                      Text(
+                        'About',
+                        style: TextStyle(fontSize: 20),
+                      ),
+                      Spacer(),
+                      Icon(
+                        Icons.question_answer,
+                        color: Colors.white,
+                      ),
+                    ],
+                  ),
+                ),
+                TextButton(
+                  onPressed: () {
+                    scaffoldKey.currentState!.closeDrawer();
+                  },
+                  child: const Row(
+                    children: [
+                      Text(
+                        'Datenschutz',
+                        style: TextStyle(fontSize: 20),
+                      ),
+                      Spacer(),
+                      Icon(
+                        Icons.privacy_tip,
+                        color: Colors.white,
+                      ),
+                    ],
+                  ),
+                ),
+                TextButton(
+                  onPressed: () {
+                    scaffoldKey.currentState!.closeDrawer();
+                  },
+                  child: const Row(
+                    children: [
+                      Text(
+                        'Impressum',
+                        style: TextStyle(fontSize: 20),
+                      ),
+                      Spacer(),
+                      Icon(
+                        Icons.apartment,
+                        color: Colors.white,
+                      ),
+                    ],
+                  ),
+                ),
+                const SizedBox(
+                  height: 250,
+                )
+              ],
+            ),
           ),
         ),
-        // Text(
-        //   'Peace of Mind \nin the\nAfterlife',
-        //   textAlign: TextAlign.center,
-        //   style: TextStyle(
-        //     fontFamily: 'JosefinSans',
-        //     height: 1.7,
-        //     letterSpacing: 8,
-        //     wordSpacing: 2,
-        //     fontWeight: FontWeight.bold,
-        //     fontSize: 32,
-        //     color: Colors.white,
-        //     decoration: TextDecoration.none,
-        //     decorationColor: Colors.white,
-        //   ),
-        // ),
-        const SizedBox(
-          height: 40,
+        bottomNavigationBar: BottomNavigationBar(
+          onTap: (value) => _bottomBarAction(value),
+          items: bottomBarButtons,
+          backgroundColor: Colors.black,
+          fixedColor: Colors.black,
         ),
-        Text(
-          'Digitale Spuren auf Knopfdruck entfernen'.toUpperCase(),
-          textAlign: TextAlign.center,
-          style: const TextStyle(
-            fontFamily: 'sans-serif',
-            fontSize: 24,
-            height: 1.6,
-            fontWeight: FontWeight.normal,
-            letterSpacing: 6,
-          ),
-        ),
-        const Spacer(),
-        Row(
-          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-          crossAxisAlignment: CrossAxisAlignment.center,
-          children: [
-            ElevatedButton.icon(
-              label: const Text('Login'),
-              onPressed: () {
-                onChangePage(Pages.login);
-              },
-              icon: const Icon(
-                Icons.login,
-                semanticLabel: 'Login',
-                size: 16,
+        body: Padding(
+          padding: const EdgeInsets.all(16.0),
+          child: Column(
+            mainAxisAlignment: MainAxisAlignment.center,
+            children: [
+              const Image(
+                image: AssetImage(
+                  'lib/assets/logo_300x200.png',
+                ),
               ),
-            ),
-            ElevatedButton.icon(
-              label: const Text('Registrieren'),
-              onPressed: () {},
-              icon: const Icon(
-                Icons.person_add,
-                semanticLabel: 'Register',
-                size: 16,
+              const SizedBox(
+                height: 40,
               ),
-            ),
-          ],
-        ),
-        // const SizedBox(
-        //   height: 32,
-        // ),
+              Text(
+                'Digitale Spuren auf Knopfdruck entfernen'.toUpperCase(),
+                textAlign: TextAlign.center,
+                style: const TextStyle(
+                  fontFamily: 'sans-serif',
+                  fontSize: 24,
+                  height: 1.6,
+                  fontWeight: FontWeight.normal,
+                  letterSpacing: 6,
+                ),
+              ),
+              // const Spacer(),
+              // Row(
+              //   mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+              //   crossAxisAlignment: CrossAxisAlignment.center,
+              //   children: widget.client?.accessToken == null
+              //       ? [
+              // ElevatedButton.icon(
+              //   label: const Text('Login'),
+              //   onPressed: () {
+              //     // onChangePage(Pages.login);
+              //     Navigator.of(context).push(
+              //       MaterialPageRoute(
+              //         builder: ((context) => LoginPage()),
+              //       ),
+              //     );
+              //   },
+              //   icon: const Icon(
+              //     Icons.login,
+              //     semanticLabel: 'Login',
+              //     size: 16,
+              //   ),
+              // ),
+              //   ElevatedButton.icon(
+              //     label: const Text('Registrieren'),
+              //     onPressed: () {},
+              //     icon: const Icon(
+              //       Icons.person_add,
+              //       semanticLabel: 'Register',
+              //       size: 16,
+              //     ),
+              //   ),
+              // ]
+              // : [],
+              // ),
+              // const SizedBox(
+              //   height: 38,
+              // ),
 
-        // const Text('data'),
-      ],
+              // const Text('data'),
+            ],
+          ),
+        ),
+      ),
     );
   }
 }

From dc3a28ba5f472c79b52e3309b267f8231f2b0152 Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Sun, 29 Oct 2023 23:58:06 +0100
Subject: [PATCH 11/24] ft/adds persistence (partial complete)

TODO: Load on start. Not working atm.
---
 frontend/app/lib/data/database.dart        | 150 +++++++++
 frontend/app/lib/gapi/client.dart          |  49 ++-
 frontend/app/lib/main.dart                 |   1 -
 frontend/app/lib/pages/dashboard_page.dart |  76 +++--
 frontend/app/lib/pages/home_page.dart      | 158 ---------
 frontend/app/lib/pages/login_page.dart     | 256 +++++++++------
 frontend/app/lib/pages/start_page.dart     | 361 +++++++++++++--------
 frontend/app/pubspec.lock                  |  29 +-
 frontend/app/pubspec.yaml                  |   3 +
 9 files changed, 642 insertions(+), 441 deletions(-)
 create mode 100644 frontend/app/lib/data/database.dart
 delete mode 100644 frontend/app/lib/pages/home_page.dart

diff --git a/frontend/app/lib/data/database.dart b/frontend/app/lib/data/database.dart
new file mode 100644
index 0000000..6d47478
--- /dev/null
+++ b/frontend/app/lib/data/database.dart
@@ -0,0 +1,150 @@
+import 'dart:async';
+import 'package:fixnum/fixnum.dart';
+
+import 'package:app/pb/google/protobuf/timestamp.pb.dart';
+import 'package:flutter/services.dart';
+import 'package:path/path.dart';
+import 'package:sqflite/sqflite.dart';
+
+class Session {
+  Session({
+    this.sessionId,
+    this.accessToken,
+    this.accessTokenExpiresAt,
+    this.refreshToken,
+    this.refreshTokenExpiresAt,
+    this.accountId,
+  }) {
+    _init();
+  }
+
+  String? sessionId;
+  String? accessToken;
+  String? refreshToken;
+  Timestamp? accessTokenExpiresAt;
+  Timestamp? refreshTokenExpiresAt;
+  Int64? accountId;
+
+  late Database _database;
+
+  Future<Database> get database async => _database;
+
+  static Future<Session> get newSession async {
+    final Database db = await openDatabase(
+      join(await getDatabasesPath(), 'df_database.db'),
+      onCreate: (db, version) {
+        return db.execute(
+          'CREATE TABLE sessions(accountId INTEGER PRIMARY KEY, sessionId TEXT, accessToken TEXT, accessTokenExpiresAt TEXT, refreshToken TEXT, refreshTokenExpiresAt TEXT)',
+        );
+      },
+      version: 1,
+    );
+    Session s = Session();
+    s._database = db;
+    return s;
+  }
+
+  void _init() {
+    _initDatabase();
+  }
+
+  Future<Database> _initDatabase() async {
+    print('DB: INITIALIZING - start');
+    _database = await openDatabase(
+      join(await getDatabasesPath(), 'df_database.db'),
+      onCreate: (db, version) {
+        return db.execute(
+          'CREATE TABLE sessions(accountId INTEGER PRIMARY KEY, sessionId TEXT, accessToken TEXT, accessTokenExpiresAt TEXT, refreshToken TEXT, refreshTokenExpiresAt TEXT)',
+        );
+      },
+      version: 1,
+    );
+    print('DB: INITIALIZING - end');
+
+    return _database;
+  }
+
+  Map<String, dynamic> toMap() {
+    return {
+      'accountId': accountId?.toInt(),
+      'sessionId': sessionId,
+      'accessToken': accessToken,
+      'accessTokenExpiresAt': accessTokenExpiresAt?.toDateTime().toString(),
+      'refreshToken': refreshToken,
+      'refreshTokenExpiresAt': refreshTokenExpiresAt?.toDateTime().toString(),
+    };
+  }
+
+  @override
+  String toString() {
+    return 'Session{accountId: $accountId, sessionId: $sessionId, accessToken: $accessToken, accessTokenExpiresAt: ${accessTokenExpiresAt.toString()}, refreshToken: $refreshToken, refreshTokenExpiresAt: ${refreshTokenExpiresAt.toString()}}';
+  }
+
+  Future<void> insertSession(Session session) async {
+    print('INSERTING SESSION: ${session.sessionId}');
+    final db = _database;
+    final result = await db.insert(
+      'sessions',
+      session.toMap(),
+      conflictAlgorithm: ConflictAlgorithm.replace,
+    );
+    print('INSERT RESULT: $result');
+  }
+
+  Future<List<Session>> getSessions() async {
+    final db = await database;
+
+    final List<Map<String, Object?>> maps = await db.query('sessions');
+
+    final List<Session> sessions = List.generate(
+      maps.length,
+      (i) {
+        print('GOT MAP: ${maps[i]}');
+
+        return Session(
+          sessionId: maps[i]['sessionId'] as String,
+          accessToken: maps[i]['accessToken'] as String,
+          accessTokenExpiresAt: Timestamp.fromDateTime(
+              DateTime.parse(maps[i]['accessTokenExpiresAt'] as String)),
+          refreshToken: maps[i]['refreshToken'] as String,
+          refreshTokenExpiresAt: Timestamp.fromDateTime(
+              DateTime.parse(maps[i]['refreshTokenExpiresAt'] as String)),
+          accountId: Int64(maps[i]['accountId'] as int),
+        );
+      },
+    );
+
+    return sessions;
+  }
+
+  static Future<Session> getSession(Int64 accountId) async {
+    final Database db = await openDatabase(
+      join(await getDatabasesPath(), 'df_database.db'),
+      onCreate: (db, version) {
+        return db.execute(
+          'CREATE TABLE sessions(accountId INTEGER PRIMARY KEY, sessionId TEXT, accessToken TEXT, accessTokenExpiresAt TEXT, refreshToken TEXT, refreshTokenExpiresAt TEXT)',
+        );
+      },
+      version: 1,
+    );
+
+    final List<Map<String, Object?>> maps = await db.query('sessions',
+        where: 'accountId = ?', whereArgs: [accountId], limit: 1);
+
+    final List<Session> sessions = List.generate(
+      maps.length,
+      (i) {
+        return Session(
+          sessionId: maps[i]['sessionId'] as String,
+          accessToken: maps[i]['accessToken'] as String,
+          accessTokenExpiresAt: maps[i]['accessTokenExpiresAt'] as Timestamp,
+          refreshToken: maps[i]['refreshToken'] as String,
+          refreshTokenExpiresAt: maps[i]['refreshTokenExpiresAt'] as Timestamp,
+          accountId: maps[i]['accountId'] as Int64,
+        );
+      },
+    );
+
+    return sessions[0];
+  }
+}
diff --git a/frontend/app/lib/gapi/client.dart b/frontend/app/lib/gapi/client.dart
index e4e225e..bacf512 100644
--- a/frontend/app/lib/gapi/client.dart
+++ b/frontend/app/lib/gapi/client.dart
@@ -1,3 +1,4 @@
+import 'package:app/data/database.dart';
 import 'package:fixnum/fixnum.dart';
 import 'package:app/pb/rpc_create_account.pb.dart';
 import 'package:app/pb/rpc_get_account_info.pb.dart';
@@ -6,12 +7,28 @@ import 'package:app/pb/service_df.pbgrpc.dart';
 import 'package:grpc/grpc.dart';
 
 class GClient {
+  GClient() {
+    // session = Session.newSession();
+    _init();
+  }
+
   String baseUrl = 'localhost';
   int port = 9090;
 
   Map<String, String> metadata = {'Authorization': ''};
-  String accessToken = '';
-  Int64 accountId = Int64();
+  // String accessToken = '';
+  // Int64 accountId = Int64();
+
+  late Session session;
+
+  static Future<GClient> get client async {
+    Session s = await Session.newSession;
+    GClient c = GClient();
+    c.session = s;
+    final sessions = await c.session.getSessions();
+    c.session = sessions[0];
+    return c;
+  }
 
   dfClient stub = dfClient(
     ClientChannel('10.0.2.2',
@@ -25,6 +42,19 @@ class GClient {
   );
   Future<void> main(List<String> args) async {}
 
+  void _init() async {
+    // print('CLIENT: INITIALIZING CLIENT - start');
+
+    session = await Session.newSession;
+    // print('CLIENT: getting sessions from database');
+
+    final sessions = await session.getSessions();
+    print('CLIENT: got sessions from database: ${sessions.toString()}');
+    session = sessions[0];
+    // print('CLIENT: INITIALIZING CLIENT - end');
+    print(session.toString());
+  }
+
   Future<CreateAccountResponse> createAccount(
       CreateAccountRequest request) async {
     try {
@@ -47,8 +77,19 @@ class GClient {
         email: email,
         password: password,
       ));
-      accessToken = response.accessToken;
-      accountId = response.accountId;
+      print(response);
+      session.accessToken = response.accessToken;
+      session.accountId = response.accountId;
+      session.sessionId = response.sessionId;
+      session.refreshToken = response.refreshToken;
+      session.accessTokenExpiresAt = response.accessTokenExpiresAt;
+      session.refreshTokenExpiresAt = response.refreshTokenExpiresAt;
+      print('GOT: ${session.toString()}');
+      try {
+        session.insertSession(session);
+      } catch (err) {
+        print('ERROR WRITING DB: $err');
+      }
       metadata['Authorization'] = 'Bearer ${response.accessToken}';
       print('auth: ${metadata['Authorization']}');
       onSuccess();
diff --git a/frontend/app/lib/main.dart b/frontend/app/lib/main.dart
index 4a983e1..78e9a9a 100644
--- a/frontend/app/lib/main.dart
+++ b/frontend/app/lib/main.dart
@@ -1,4 +1,3 @@
-import 'package:app/pages/home_page.dart';
 import 'package:app/pages/start_page.dart';
 import 'package:app/widgets/background.dart';
 import 'package:flutter/material.dart';
diff --git a/frontend/app/lib/pages/dashboard_page.dart b/frontend/app/lib/pages/dashboard_page.dart
index 012d74a..70a1ea9 100644
--- a/frontend/app/lib/pages/dashboard_page.dart
+++ b/frontend/app/lib/pages/dashboard_page.dart
@@ -5,29 +5,8 @@ import 'package:app/widgets/background.dart';
 import 'package:app/widgets/loading_widget.dart';
 import 'package:flutter/material.dart';
 
-GlobalKey<ScaffoldState> scaffolKey = GlobalKey<ScaffoldState>();
-
-List<BottomNavigationBarItem> bottomBarButtons = const [
-  BottomNavigationBarItem(
-    label: 'Zurueck',
-    backgroundColor: Colors.white,
-    icon: Icon(
-      Icons.arrow_back,
-      color: Colors.white,
-    ),
-  ),
-  BottomNavigationBarItem(
-    backgroundColor: Colors.white,
-    label: 'AccountInf',
-    icon: Icon(
-      Icons.person,
-      color: Colors.white,
-    ),
-  ),
-];
-
 class DashboardPage extends StatefulWidget {
-  DashboardPage({super.key, required this.client});
+  const DashboardPage({super.key, required this.client});
 
   final GClient client;
 
@@ -48,15 +27,15 @@ class _DashboardPageState extends State<DashboardPage> {
   @override
   void initState() {
     super.initState();
-    if (widget.client.accessToken == '') {
-      Navigator.of(context).pop();
-      return;
-    }
+    // if (widget.client.session.accessToken == '') {
+    //   Navigator.of(context).pop();
+    //   return;
+    // }
 
     _setLoading(true);
     widget.client.getAccountInfo(
       GetAccountInfoRequest(
-        accountId: widget.client.accountId,
+        accountId: widget.client.session?.accountId,
       ),
       onError: () {
         ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
@@ -73,7 +52,6 @@ class _DashboardPageState extends State<DashboardPage> {
   Widget build(BuildContext context) {
     return Background(
       child: Scaffold(
-        key: scaffolKey,
         appBar: AppBar(
           automaticallyImplyLeading: false,
           flexibleSpace: Image.asset(
@@ -81,10 +59,7 @@ class _DashboardPageState extends State<DashboardPage> {
             height: 80,
           ),
         ),
-        bottomNavigationBar: BottomNavigationBar(
-          items: bottomBarButtons,
-          backgroundColor: Colors.black,
-        ),
+        bottomNavigationBar: BottomBar(),
         body: !_loading
             ? Background(
                 child: Center(
@@ -108,3 +83,40 @@ class _DashboardPageState extends State<DashboardPage> {
     );
   }
 }
+
+class BottomBar extends StatelessWidget {
+  const BottomBar({
+    super.key,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return BottomNavigationBar(
+      items: [
+        BottomNavigationBarItem(
+          label: 'back',
+          backgroundColor: Colors.white,
+          icon: IconButton(
+            onPressed: () => Navigator.of(context).pop(),
+            icon: const Icon(
+              Icons.arrow_back,
+              color: Colors.white,
+            ),
+          ),
+        ),
+        BottomNavigationBarItem(
+          backgroundColor: Colors.white,
+          label: 'Menu',
+          icon: IconButton(
+            onPressed: () => Scaffold.of(context).openDrawer(),
+            icon: const Icon(
+              Icons.person,
+              color: Colors.white,
+            ),
+          ),
+        ),
+      ],
+      backgroundColor: Colors.black,
+    );
+  }
+}
diff --git a/frontend/app/lib/pages/home_page.dart b/frontend/app/lib/pages/home_page.dart
deleted file mode 100644
index 6b544e8..0000000
--- a/frontend/app/lib/pages/home_page.dart
+++ /dev/null
@@ -1,158 +0,0 @@
-import 'package:app/gapi/client.dart';
-import 'package:app/pages/login_page.dart';
-import 'package:app/pages/start_page.dart';
-import 'package:flutter/material.dart';
-import 'package:app/pages/pages.dart';
-
-Map<Pages, List<BottomNavigationBarItem>> bottomBarButtons = {
-  Pages.start: const [
-    BottomNavigationBarItem(
-      label: 'Zurueck',
-      backgroundColor: Colors.white,
-      icon: Icon(
-        Icons.arrow_back,
-        color: Colors.white,
-      ),
-    ),
-    BottomNavigationBarItem(
-      backgroundColor: Colors.white,
-      label: 'AccountInf',
-      icon: Icon(
-        Icons.person,
-        color: Colors.white,
-      ),
-    ),
-  ],
-  Pages.persons: const [
-    BottomNavigationBarItem(
-      label: 'Zurueck',
-      backgroundColor: Colors.white,
-      icon: Icon(
-        Icons.arrow_back,
-        color: Colors.white,
-      ),
-    ),
-    BottomNavigationBarItem(
-      backgroundColor: Colors.white,
-      label: 'AccountInf',
-      icon: Icon(
-        Icons.person,
-        color: Colors.white,
-      ),
-    ),
-  ],
-  Pages.about: const [
-    BottomNavigationBarItem(
-      label: 'Zurueck',
-      backgroundColor: Colors.white,
-      icon: Icon(
-        Icons.arrow_back,
-        color: Colors.white,
-      ),
-    ),
-    BottomNavigationBarItem(
-      backgroundColor: Colors.white,
-      label: 'AccountInf',
-      icon: Icon(
-        Icons.person,
-        color: Colors.white,
-      ),
-    ),
-  ],
-  Pages.login: const [
-    BottomNavigationBarItem(
-      label: 'Zurueck',
-      backgroundColor: Colors.white,
-      icon: Icon(
-        Icons.arrow_back,
-        color: Colors.white,
-      ),
-    ),
-    BottomNavigationBarItem(
-      backgroundColor: Colors.white,
-      label: 'AccountInf',
-      icon: Icon(
-        Icons.person,
-        color: Colors.white,
-      ),
-    ),
-  ]
-};
-
-class HomePage extends StatefulWidget {
-  const HomePage({super.key});
-
-  @override
-  State<HomePage> createState() => _HomePageState();
-}
-
-class _HomePageState extends State<HomePage> {
-  bool _loading = false;
-
-  Pages _selectedPage = Pages.start;
-
-  Widget _selectPage(Pages page) {
-    switch (page) {
-      case Pages.login:
-        return LoginPage(
-            // onChangePage: changePage,
-            );
-      default:
-        return StartPage(
-            // onChangePage: changePage,
-            );
-    }
-  }
-
-  Future<bool> _onWillPop() async {
-    changePage(Pages.start);
-    return false;
-  }
-
-  void changePage(Pages page) {
-    if (!Pages.values.contains(page)) {
-      page = _selectedPage;
-    }
-    setState(() {
-      _selectedPage = page;
-    });
-  }
-
-  void _setLoading(bool loading) {
-    setState(() {
-      _loading = loading;
-    });
-  }
-
-  final GClient client = GClient();
-
-  @override
-  Widget build(BuildContext context) {
-    return Scaffold(
-      appBar: _selectedPage == Pages.start
-          ? AppBar(
-              automaticallyImplyLeading: false,
-            )
-          : AppBar(
-              automaticallyImplyLeading: false,
-              flexibleSpace: Image.asset(
-                'lib/assets/logo_300x200.png',
-                height: 80,
-              ),
-            ),
-      bottomNavigationBar: BottomNavigationBar(
-        items: bottomBarButtons[_selectedPage]!.toList(),
-        backgroundColor: Colors.black,
-      ),
-      body: Container(
-        padding: const EdgeInsets.fromLTRB(16, 32, 16, 32),
-        child: Center(
-          child: WillPopScope(
-            child: _selectPage(_selectedPage),
-            onWillPop: () => _onWillPop(),
-          ),
-        ),
-      ),
-    );
-  }
-}
diff --git a/frontend/app/lib/pages/login_page.dart b/frontend/app/lib/pages/login_page.dart
index 9daad16..334911e 100644
--- a/frontend/app/lib/pages/login_page.dart
+++ b/frontend/app/lib/pages/login_page.dart
@@ -5,29 +5,7 @@ import 'package:app/widgets/loading_widget.dart';
 import 'package:flutter/material.dart';
 import 'package:grpc/grpc.dart';
 
-GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
-
-List<BottomNavigationBarItem> bottomBarButtons = [
-  const BottomNavigationBarItem(
-    label: 'back',
-    backgroundColor: Colors.white,
-    icon: Icon(
-      Icons.arrow_back,
-      color: Colors.white,
-    ),
-  ),
-  BottomNavigationBarItem(
-    backgroundColor: Colors.white,
-    label: 'Menu',
-    icon: IconButton(
-      onPressed: () => scaffoldKey.currentState!.openDrawer(),
-      icon: const Icon(
-        Icons.menu,
-        color: Colors.white,
-      ),
-    ),
-  ),
-];
+// GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
 
 class LoginPage extends StatefulWidget {
   LoginPage({
@@ -43,16 +21,46 @@ class LoginPage extends StatefulWidget {
 
 class _LoginPageState extends State<LoginPage> {
   bool _loading = false;
+  final List<BottomNavigationBarItem> bottombarButtons = [];
 
-  List<BottomNavigationBarItem> _selectedBottomBarButtons = bottomBarButtons;
+  // List<BottomNavigationBarItem> _selectedBottomBarButtons = bottomBarButtons;
+  @override
+  void initState() {
+    super.initState();
+    _addBottomBarButtons();
+  }
 
   void _bottomBarAction(int index) {
-    switch (_selectedBottomBarButtons[index].label?.toLowerCase()) {
+    switch (bottombarButtons[index].label?.toLowerCase()) {
       case 'back':
         Navigator.of(context).pop();
     }
   }
 
+  void _addBottomBarButtons() {
+    bottombarButtons.addAll([
+      const BottomNavigationBarItem(
+        label: 'back',
+        backgroundColor: Colors.white,
+        icon: Icon(
+          Icons.arrow_back,
+          color: Colors.white,
+        ),
+      ),
+      BottomNavigationBarItem(
+        backgroundColor: Colors.white,
+        label: 'Menu',
+        icon: IconButton(
+          onPressed: () => Scaffold.of(context).openDrawer(),
+          icon: const Icon(
+            Icons.menu,
+            color: Colors.white,
+          ),
+        ),
+      ),
+    ]);
+  }
+
   void _setLoading(bool loading) {
     setState(() {
       _loading = loading;
@@ -69,7 +77,6 @@ class _LoginPageState extends State<LoginPage> {
   Widget build(BuildContext context) {
     return Background(
       child: Scaffold(
-        key: scaffoldKey,
         appBar: AppBar(
           automaticallyImplyLeading: false,
           // flexibleSpace: Image.asset(
@@ -77,81 +84,8 @@ class _LoginPageState extends State<LoginPage> {
           //   height: 80,
           // ),
         ),
-        bottomNavigationBar: BottomNavigationBar(
-          items: bottomBarButtons,
-          backgroundColor: Colors.black,
-          fixedColor: Colors.black,
-          onTap: (value) => _bottomBarAction(value),
-        ),
-        drawer: Drawer(
-          backgroundColor: Colors.black,
-          child: Padding(
-            padding: const EdgeInsets.all(40.0),
-            child: Column(
-              mainAxisAlignment: MainAxisAlignment.center,
-              children: [
-                const Spacer(),
-                TextButton(
-                  onPressed: () {
-                    scaffoldKey.currentState!.closeDrawer();
-                  },
-                  child: const Row(
-                    children: [
-                      Text(
-                        'About',
-                        style: TextStyle(fontSize: 20),
-                      ),
-                      Spacer(),
-                      Icon(
-                        Icons.question_answer,
-                        color: Colors.white,
-                      ),
-                    ],
-                  ),
-                ),
-                TextButton(
-                  onPressed: () {
-                    scaffoldKey.currentState!.closeDrawer();
-                  },
-                  child: const Row(
-                    children: [
-                      Text(
-                        'Datenschutz',
-                        style: TextStyle(fontSize: 20),
-                      ),
-                      Spacer(),
-                      Icon(
-                        Icons.privacy_tip,
-                        color: Colors.white,
-                      ),
-                    ],
-                  ),
-                ),
-                TextButton(
-                  onPressed: () {
-                    scaffoldKey.currentState!.closeDrawer();
-                  },
-                  child: const Row(
-                    children: [
-                      Text(
-                        'Impressum',
-                        style: TextStyle(fontSize: 20),
-                      ),
-                      Spacer(),
-                      Icon(
-                        Icons.apartment,
-                        color: Colors.white,
-                      ),
-                    ],
-                  ),
-                ),
-                const SizedBox(
-                  height: 250,
-                )
-              ],
-            ),
-          ),
-        ),
+        bottomNavigationBar: const BottomBar(),
+        drawer: const SideDrawer(),
         body: !_loading
             ? Form(
                 key: _formKey,
@@ -227,7 +161,7 @@ class _LoginPageState extends State<LoginPage> {
                             return null;
                           },
                         ),
-                        SizedBox(
+                        const SizedBox(
                           height: 15,
                         ),
                         ElevatedButton(
@@ -322,3 +256,121 @@ class _LoginPageState extends State<LoginPage> {
     );
   }
 }
+
+class SideDrawer extends StatelessWidget {
+  const SideDrawer({
+    super.key,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Drawer(
+      backgroundColor: Colors.black,
+      child: Padding(
+        padding: const EdgeInsets.all(40.0),
+        child: Column(
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: [
+            const Spacer(),
+            TextButton(
+              onPressed: () {
+                Scaffold.of(context).closeDrawer();
+              },
+              child: const Row(
+                children: [
+                  Text(
+                    'About',
+                    style: TextStyle(fontSize: 20),
+                  ),
+                  Spacer(),
+                  Icon(
+                    Icons.question_answer,
+                    color: Colors.white,
+                  ),
+                ],
+              ),
+            ),
+            TextButton(
+              onPressed: () {
+                Scaffold.of(context).closeDrawer();
+              },
+              child: const Row(
+                children: [
+                  Text(
+                    'Datenschutz',
+                    style: TextStyle(fontSize: 20),
+                  ),
+                  Spacer(),
+                  Icon(
+                    Icons.privacy_tip,
+                    color: Colors.white,
+                  ),
+                ],
+              ),
+            ),
+            TextButton(
+              onPressed: () {
+                Scaffold.of(context).closeDrawer();
+              },
+              child: const Row(
+                children: [
+                  Text(
+                    'Impressum',
+                    style: TextStyle(fontSize: 20),
+                  ),
+                  Spacer(),
+                  Icon(
+                    Icons.apartment,
+                    color: Colors.white,
+                  ),
+                ],
+              ),
+            ),
+            const SizedBox(
+              height: 250,
+            )
+          ],
+        ),
+      ),
+    );
+  }
+}
+
+class BottomBar extends StatelessWidget {
+  const BottomBar({
+    super.key,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return BottomNavigationBar(
+      items: [
+        BottomNavigationBarItem(
+          label: 'back',
+          backgroundColor: Colors.white,
+          icon: IconButton(
+            onPressed: () => Navigator.of(context).pop(),
+            icon: const Icon(
+              Icons.arrow_back,
+              color: Colors.white,
+            ),
+          ),
+        ),
+        BottomNavigationBarItem(
+          backgroundColor: Colors.white,
+          label: 'Menu',
+          icon: IconButton(
+            onPressed: () => Scaffold.of(context).openDrawer(),
+            icon: const Icon(
+              Icons.menu,
+              color: Colors.white,
+            ),
+          ),
+        ),
+      ],
+      backgroundColor: Colors.black,
+      fixedColor: Colors.black,
+      // onTap: (value) => _bottomBarAction(value),
+    );
+  }
+}
diff --git a/frontend/app/lib/pages/start_page.dart b/frontend/app/lib/pages/start_page.dart
index c1a6d59..308619a 100644
--- a/frontend/app/lib/pages/start_page.dart
+++ b/frontend/app/lib/pages/start_page.dart
@@ -4,170 +4,41 @@ import 'package:app/widgets/background.dart';
 import 'package:flutter/material.dart';
 import 'dart:core';
 
-GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
-
-List<BottomNavigationBarItem> bottomBarButtons = [
-  const BottomNavigationBarItem(
-    label: 'register',
-    backgroundColor: Colors.white,
-    icon: Column(
-      children: [
-        Icon(
-          Icons.person_add,
-          color: Colors.white,
-        ),
-        Text(
-          'Registrieren',
-          style: TextStyle(
-            color: Colors.white,
-            fontSize: 16,
-          ),
-        )
-      ],
-    ),
-  ),
-  const BottomNavigationBarItem(
-    label: 'login',
-    backgroundColor: Colors.white,
-    icon: Column(
-      children: [
-        Icon(
-          Icons.login,
-          color: Colors.white,
-        ),
-        Text(
-          'Login',
-          style: TextStyle(
-            color: Colors.white,
-            fontSize: 16,
-          ),
-        )
-      ],
-    ),
-  ),
-  BottomNavigationBarItem(
-    backgroundColor: Colors.white,
-    label: 'Menu',
-    icon: IconButton(
-      onPressed: () => scaffoldKey.currentState!.openDrawer(),
-      icon: const Icon(
-        Icons.menu,
-        color: Colors.white,
-      ),
-    ),
-  ),
-];
-
 class StartPage extends StatefulWidget {
   StartPage({
     super.key,
     this.client,
   });
 
-  final GClient? client;
+  GClient? client;
 
   @override
   State<StartPage> createState() => _StartPageState();
 }
 
 class _StartPageState extends State<StartPage> {
-  List<BottomNavigationBarItem> _selectedBottomBarButtons = bottomBarButtons;
+  // List<BottomNavigationBarItem> _selectedBottomBarButtons = bottomBarButtons;
+  final List<BottomNavigationBarItem> bottombarButtons = [];
 
-  void _bottomBarAction(int index) {
-    switch (_selectedBottomBarButtons[index].label?.toLowerCase()) {
-      case 'login':
-        Navigator.of(context)
-            .push(MaterialPageRoute(builder: (context) => LoginPage()));
-    }
+  void _init() async {
+    widget.client ??= await GClient.client;
+  }
+
+  @override
+  void initState() {
+    _init();
+    super.initState();
   }
 
   @override
   Widget build(BuildContext context) {
     return Background(
       child: Scaffold(
-        key: scaffoldKey,
         appBar: AppBar(
           automaticallyImplyLeading: false,
-          // flexibleSpace: Image.asset(
-          //   'lib/assets/logo_300x200.png',
-          //   height: 80,
-          // ),
-        ),
-        drawer: Drawer(
-          backgroundColor: Colors.black,
-          child: Padding(
-            padding: const EdgeInsets.all(40.0),
-            child: Column(
-              mainAxisAlignment: MainAxisAlignment.center,
-              children: [
-                const Spacer(),
-                TextButton(
-                  onPressed: () {
-                    scaffoldKey.currentState!.closeDrawer();
-                  },
-                  child: const Row(
-                    children: [
-                      Text(
-                        'About',
-                        style: TextStyle(fontSize: 20),
-                      ),
-                      Spacer(),
-                      Icon(
-                        Icons.question_answer,
-                        color: Colors.white,
-                      ),
-                    ],
-                  ),
-                ),
-                TextButton(
-                  onPressed: () {
-                    scaffoldKey.currentState!.closeDrawer();
-                  },
-                  child: const Row(
-                    children: [
-                      Text(
-                        'Datenschutz',
-                        style: TextStyle(fontSize: 20),
-                      ),
-                      Spacer(),
-                      Icon(
-                        Icons.privacy_tip,
-                        color: Colors.white,
-                      ),
-                    ],
-                  ),
-                ),
-                TextButton(
-                  onPressed: () {
-                    scaffoldKey.currentState!.closeDrawer();
-                  },
-                  child: const Row(
-                    children: [
-                      Text(
-                        'Impressum',
-                        style: TextStyle(fontSize: 20),
-                      ),
-                      Spacer(),
-                      Icon(
-                        Icons.apartment,
-                        color: Colors.white,
-                      ),
-                    ],
-                  ),
-                ),
-                const SizedBox(
-                  height: 250,
-                )
-              ],
-            ),
-          ),
-        ),
-        bottomNavigationBar: BottomNavigationBar(
-          onTap: (value) => _bottomBarAction(value),
-          items: bottomBarButtons,
-          backgroundColor: Colors.black,
-          fixedColor: Colors.black,
         ),
+        drawer: const SideDrawer(),
+        bottomNavigationBar: BottomBar(widget: widget),
         body: Padding(
           padding: const EdgeInsets.all(16.0),
           child: Column(
@@ -192,6 +63,16 @@ class _StartPageState extends State<StartPage> {
                   letterSpacing: 6,
                 ),
               ),
+              TextButton(
+                onPressed: () {
+                  final s = widget.client?.session.getSessions();
+                  print(s);
+                  print(widget.client?.session.accessToken);
+                },
+                child: const Text(
+                  "GET SESSIONS",
+                ),
+              ),
               // const Spacer(),
               // Row(
               //   mainAxisAlignment: MainAxisAlignment.spaceEvenly,
@@ -238,3 +119,199 @@ class _StartPageState extends State<StartPage> {
     );
   }
 }
+
+class SideDrawer extends StatelessWidget {
+  const SideDrawer({
+    super.key,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Drawer(
+      backgroundColor: Colors.black,
+      child: Padding(
+        padding: const EdgeInsets.all(40.0),
+        child: Column(
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: [
+            const Spacer(),
+            TextButton(
+              onPressed: () {
+                Scaffold.of(context).closeDrawer();
+              },
+              child: const Row(
+                children: [
+                  Text(
+                    'About',
+                    style: TextStyle(fontSize: 20),
+                  ),
+                  Spacer(),
+                  Icon(
+                    Icons.question_answer,
+                    color: Colors.white,
+                  ),
+                ],
+              ),
+            ),
+            TextButton(
+              onPressed: () {
+                Scaffold.of(context).closeDrawer();
+              },
+              child: const Row(
+                children: [
+                  Text(
+                    'Datenschutz',
+                    style: TextStyle(fontSize: 20),
+                  ),
+                  Spacer(),
+                  Icon(
+                    Icons.privacy_tip,
+                    color: Colors.white,
+                  ),
+                ],
+              ),
+            ),
+            TextButton(
+              onPressed: () {
+                Scaffold.of(context).closeDrawer();
+              },
+              child: const Row(
+                children: [
+                  Text(
+                    'Impressum',
+                    style: TextStyle(fontSize: 20),
+                  ),
+                  Spacer(),
+                  Icon(
+                    Icons.apartment,
+                    color: Colors.white,
+                  ),
+                ],
+              ),
+            ),
+            const SizedBox(
+              height: 250,
+            )
+          ],
+        ),
+      ),
+    );
+  }
+}
+
+class BottomBar extends StatelessWidget {
+  const BottomBar({
+    super.key,
+    required this.widget,
+  });
+
+  final StartPage widget;
+
+  @override
+  Widget build(BuildContext context) {
+    return BottomNavigationBar(
+      // onTap: (value) => _bottomBarAction(value),
+      items: widget.client?.session.accessToken != null
+          ? [
+              BottomNavigationBarItem(
+                backgroundColor: Colors.white,
+                label: 'Personen',
+                icon: Column(
+                  children: [
+                    IconButton(
+                      onPressed: () => Scaffold.of(context).openDrawer(),
+                      icon: const Icon(
+                        Icons.group,
+                        color: Colors.white,
+                      ),
+                    ),
+                    const Text(
+                      'Personen',
+                      style: TextStyle(
+                        color: Colors.white,
+                        fontSize: 16,
+                      ),
+                    )
+                  ],
+                ),
+              ),
+              BottomNavigationBarItem(
+                backgroundColor: Colors.white,
+                label: 'Menu',
+                icon: IconButton(
+                  onPressed: () => Scaffold.of(context).openDrawer(),
+                  icon: const Icon(
+                    Icons.menu,
+                    color: Colors.white,
+                  ),
+                ),
+              )
+            ]
+          : [
+              BottomNavigationBarItem(
+                label: 'register',
+                backgroundColor: Colors.white,
+                icon: Column(
+                  children: [
+                    IconButton(
+                      onPressed: () {
+                        Navigator.of(context).push(MaterialPageRoute(
+                            builder: (context) => LoginPage()));
+                      },
+                      icon: const Icon(
+                        Icons.login,
+                        color: Colors.white,
+                      ),
+                    ),
+                    const Text(
+                      'Registrieren',
+                      style: TextStyle(
+                        color: Colors.white,
+                        fontSize: 16,
+                      ),
+                    )
+                  ],
+                ),
+              ),
+              BottomNavigationBarItem(
+                label: 'login',
+                backgroundColor: Colors.white,
+                icon: Column(
+                  children: [
+                    IconButton(
+                      onPressed: () {
+                        Navigator.of(context).push(MaterialPageRoute(
+                            builder: (context) => LoginPage()));
+                      },
+                      icon: const Icon(
+                        Icons.login,
+                        color: Colors.white,
+                      ),
+                    ),
+                    const Text(
+                      'Login',
+                      style: TextStyle(
+                        color: Colors.white,
+                        fontSize: 16,
+                      ),
+                    )
+                  ],
+                ),
+              ),
+              BottomNavigationBarItem(
+                backgroundColor: Colors.white,
+                label: 'Menu',
+                icon: IconButton(
+                  onPressed: () => Scaffold.of(context).openDrawer(),
+                  icon: const Icon(
+                    Icons.menu,
+                    color: Colors.white,
+                  ),
+                ),
+              ),
+            ],
+      backgroundColor: Colors.black,
+      fixedColor: Colors.black,
+    );
+  }
+}
diff --git a/frontend/app/pubspec.lock b/frontend/app/pubspec.lock
index 687c22e..9323a01 100644
--- a/frontend/app/pubspec.lock
+++ b/frontend/app/pubspec.lock
@@ -90,7 +90,7 @@ packages:
     source: hosted
     version: "1.3.1"
   fixnum:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: fixnum
       sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
@@ -196,7 +196,7 @@ packages:
     source: hosted
     version: "1.9.1"
   path:
-    dependency: transitive
+    dependency: "direct main"
     description:
       name: path
       sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917"
@@ -232,6 +232,22 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.10.0"
+  sqflite:
+    dependency: "direct main"
+    description:
+      name: sqflite
+      sha256: "591f1602816e9c31377d5f008c2d9ef7b8aca8941c3f89cc5fd9d84da0c38a9a"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.3.0"
+  sqflite_common:
+    dependency: transitive
+    description:
+      name: sqflite_common
+      sha256: "1b92f368f44b0dee2425bb861cfa17b6f6cf3961f762ff6f941d20b33355660a"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.5.0"
   stack_trace:
     dependency: transitive
     description:
@@ -256,6 +272,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.2.0"
+  synchronized:
+    dependency: transitive
+    description:
+      name: synchronized
+      sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.1.0"
   term_glyph:
     dependency: transitive
     description:
@@ -298,3 +322,4 @@ packages:
     version: "0.1.4-beta"
 sdks:
   dart: ">=3.1.4 <4.0.0"
+  flutter: ">=3.3.0"
diff --git a/frontend/app/pubspec.yaml b/frontend/app/pubspec.yaml
index 07e48bb..f28d267 100644
--- a/frontend/app/pubspec.yaml
+++ b/frontend/app/pubspec.yaml
@@ -39,6 +39,9 @@ dependencies:
   # Use with the CupertinoIcons class for iOS style icons.
   cupertino_icons: ^1.0.2
   grpc: ^3.2.4
+  sqflite: ^2.3.0
+  path: ^1.8.3
+  fixnum: ^1.1.0
 
 dev_dependencies:
   lints: ^2.0.0

From 0c0b0b45949ea0865122b578305726fbc6a647ed Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Mon, 30 Oct 2023 00:38:03 +0100
Subject: [PATCH 12/24] ft/adds persistence

TODO: Logout function
---
 frontend/app/lib/data/database.dart    |  5 ++++
 frontend/app/lib/pages/start_page.dart | 37 +++++++++++++++++++++++---
 2 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/frontend/app/lib/data/database.dart b/frontend/app/lib/data/database.dart
index 6d47478..6342ddb 100644
--- a/frontend/app/lib/data/database.dart
+++ b/frontend/app/lib/data/database.dart
@@ -91,6 +91,11 @@ class Session {
     print('INSERT RESULT: $result');
   }
 
+  Future<void> removeSession(String sessionId) async {
+    final db = _database;
+    await db.delete('sessions', where: 'sessionId = ?', whereArgs: [sessionId]);
+  }
+
   Future<List<Session>> getSessions() async {
     final db = await database;
 
diff --git a/frontend/app/lib/pages/start_page.dart b/frontend/app/lib/pages/start_page.dart
index 308619a..b106f3b 100644
--- a/frontend/app/lib/pages/start_page.dart
+++ b/frontend/app/lib/pages/start_page.dart
@@ -21,7 +21,10 @@ class _StartPageState extends State<StartPage> {
   final List<BottomNavigationBarItem> bottombarButtons = [];
 
   void _init() async {
-    widget.client ??= await GClient.client;
+    final c = await GClient.client;
+    setState(() {
+      widget.client = c;
+    });
   }
 
   @override
@@ -37,7 +40,14 @@ class _StartPageState extends State<StartPage> {
         appBar: AppBar(
           automaticallyImplyLeading: false,
         ),
-        drawer: const SideDrawer(),
+        drawer: SideDrawer(
+          onLogout: () {
+            setState(() {
+              widget.client?.session
+                  .removeSession(widget.client!.session.sessionId!);
+            });
+          },
+        ),
         bottomNavigationBar: BottomBar(widget: widget),
         body: Padding(
           padding: const EdgeInsets.all(16.0),
@@ -121,10 +131,13 @@ class _StartPageState extends State<StartPage> {
 }
 
 class SideDrawer extends StatelessWidget {
-  const SideDrawer({
+  SideDrawer({
     super.key,
+    required this.onLogout,
   });
 
+  Function() onLogout;
+
   @override
   Widget build(BuildContext context) {
     return Drawer(
@@ -189,6 +202,24 @@ class SideDrawer extends StatelessWidget {
                 ],
               ),
             ),
+            TextButton(
+              onPressed: () {
+                onLogout();
+              },
+              child: const Row(
+                children: [
+                  Text(
+                    'Log out',
+                    style: TextStyle(fontSize: 20),
+                  ),
+                  Spacer(),
+                  Icon(
+                    Icons.logout,
+                    color: Colors.white,
+                  ),
+                ],
+              ),
+            ),
             const SizedBox(
               height: 250,
             )

From f41236e3041a9f71480b3296df9436b17d0f218b Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Mon, 30 Oct 2023 22:48:37 +0100
Subject: [PATCH 13/24] rf/extracts bottomnavigationbar & drawer

---
 frontend/app/lib/data/database.dart        |  19 +-
 frontend/app/lib/gapi/client.dart          |  23 +-
 frontend/app/lib/pages/dashboard_page.dart |   2 +-
 frontend/app/lib/pages/login_page.dart     | 208 ++++------
 frontend/app/lib/pages/start_page.dart     | 462 +++++++++------------
 frontend/app/lib/widgets/bottom_bar.dart   |  20 +
 frontend/app/lib/widgets/side_drawer.dart  |  29 ++
 7 files changed, 346 insertions(+), 417 deletions(-)
 create mode 100644 frontend/app/lib/widgets/bottom_bar.dart
 create mode 100644 frontend/app/lib/widgets/side_drawer.dart

diff --git a/frontend/app/lib/data/database.dart b/frontend/app/lib/data/database.dart
index 6342ddb..f5d42d8 100644
--- a/frontend/app/lib/data/database.dart
+++ b/frontend/app/lib/data/database.dart
@@ -2,7 +2,6 @@ import 'dart:async';
 import 'package:fixnum/fixnum.dart';
 
 import 'package:app/pb/google/protobuf/timestamp.pb.dart';
-import 'package:flutter/services.dart';
 import 'package:path/path.dart';
 import 'package:sqflite/sqflite.dart';
 
@@ -49,7 +48,7 @@ class Session {
   }
 
   Future<Database> _initDatabase() async {
-    print('DB: INITIALIZING - start');
+    // print('DB: INITIALIZING - start');
     _database = await openDatabase(
       join(await getDatabasesPath(), 'df_database.db'),
       onCreate: (db, version) {
@@ -59,7 +58,7 @@ class Session {
       },
       version: 1,
     );
-    print('DB: INITIALIZING - end');
+    // print('DB: INITIALIZING - end');
 
     return _database;
   }
@@ -81,19 +80,25 @@ class Session {
   }
 
   Future<void> insertSession(Session session) async {
-    print('INSERTING SESSION: ${session.sessionId}');
+    // print('INSERTING SESSION: ${session.sessionId}');
     final db = _database;
-    final result = await db.insert(
+    await db.insert(
       'sessions',
       session.toMap(),
       conflictAlgorithm: ConflictAlgorithm.replace,
     );
-    print('INSERT RESULT: $result');
+    // print('INSERT RESULT: $result');
   }
 
   Future<void> removeSession(String sessionId) async {
     final db = _database;
     await db.delete('sessions', where: 'sessionId = ?', whereArgs: [sessionId]);
+    this.sessionId = null;
+    refreshToken = null;
+    accessTokenExpiresAt = null;
+    refreshTokenExpiresAt = null;
+    accountId = null;
+    accessToken = null;
   }
 
   Future<List<Session>> getSessions() async {
@@ -104,7 +109,7 @@ class Session {
     final List<Session> sessions = List.generate(
       maps.length,
       (i) {
-        print('GOT MAP: ${maps[i]}');
+        // print('GOT MAP: ${maps[i]}');
 
         return Session(
           sessionId: maps[i]['sessionId'] as String,
diff --git a/frontend/app/lib/gapi/client.dart b/frontend/app/lib/gapi/client.dart
index bacf512..aae5a46 100644
--- a/frontend/app/lib/gapi/client.dart
+++ b/frontend/app/lib/gapi/client.dart
@@ -8,7 +8,6 @@ import 'package:grpc/grpc.dart';
 
 class GClient {
   GClient() {
-    // session = Session.newSession();
     _init();
   }
 
@@ -16,8 +15,6 @@ class GClient {
   int port = 9090;
 
   Map<String, String> metadata = {'Authorization': ''};
-  // String accessToken = '';
-  // Int64 accountId = Int64();
 
   late Session session;
 
@@ -43,16 +40,10 @@ class GClient {
   Future<void> main(List<String> args) async {}
 
   void _init() async {
-    // print('CLIENT: INITIALIZING CLIENT - start');
-
     session = await Session.newSession;
-    // print('CLIENT: getting sessions from database');
 
     final sessions = await session.getSessions();
-    print('CLIENT: got sessions from database: ${sessions.toString()}');
     session = sessions[0];
-    // print('CLIENT: INITIALIZING CLIENT - end');
-    print(session.toString());
   }
 
   Future<CreateAccountResponse> createAccount(
@@ -60,9 +51,7 @@ class GClient {
     try {
       final response = stub.createAccount(request);
       return response;
-    } catch (e) {
-      print('caught error: $e');
-    }
+    } catch (e) {}
     return CreateAccountResponse();
   }
 
@@ -77,23 +66,18 @@ class GClient {
         email: email,
         password: password,
       ));
-      print(response);
       session.accessToken = response.accessToken;
       session.accountId = response.accountId;
       session.sessionId = response.sessionId;
       session.refreshToken = response.refreshToken;
       session.accessTokenExpiresAt = response.accessTokenExpiresAt;
       session.refreshTokenExpiresAt = response.refreshTokenExpiresAt;
-      print('GOT: ${session.toString()}');
       try {
         session.insertSession(session);
-      } catch (err) {
-        print('ERROR WRITING DB: $err');
-      }
+      } catch (err) {}
       metadata['Authorization'] = 'Bearer ${response.accessToken}';
-      print('auth: ${metadata['Authorization']}');
       onSuccess();
-      // return response;
+      return response;
     } on GrpcError catch (e) {
       print('caught error: ${e.message}');
       metadata['Authorization'] = '';
@@ -109,7 +93,6 @@ class GClient {
   Future<GetAccountInfoResponse> getAccountInfo(GetAccountInfoRequest request,
       {required Function onError}) async {
     try {
-      // Map<String, String> metadata = {'Authorization': 'Bearer $token'};
       final response = await stub.getAccountInfo(
         request,
         options: CallOptions(
diff --git a/frontend/app/lib/pages/dashboard_page.dart b/frontend/app/lib/pages/dashboard_page.dart
index 70a1ea9..6db7ed0 100644
--- a/frontend/app/lib/pages/dashboard_page.dart
+++ b/frontend/app/lib/pages/dashboard_page.dart
@@ -35,7 +35,7 @@ class _DashboardPageState extends State<DashboardPage> {
     _setLoading(true);
     widget.client.getAccountInfo(
       GetAccountInfoRequest(
-        accountId: widget.client.session?.accountId,
+        accountId: widget.client.session.accountId,
       ),
       onError: () {
         ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
diff --git a/frontend/app/lib/pages/login_page.dart b/frontend/app/lib/pages/login_page.dart
index 334911e..4856e08 100644
--- a/frontend/app/lib/pages/login_page.dart
+++ b/frontend/app/lib/pages/login_page.dart
@@ -1,7 +1,9 @@
 import 'package:app/gapi/client.dart';
 import 'package:app/pages/start_page.dart';
 import 'package:app/widgets/background.dart';
+import 'package:app/widgets/bottom_bar.dart';
 import 'package:app/widgets/loading_widget.dart';
+import 'package:app/widgets/side_drawer.dart';
 import 'package:flutter/material.dart';
 import 'package:grpc/grpc.dart';
 
@@ -84,8 +86,92 @@ class _LoginPageState extends State<LoginPage> {
           //   height: 80,
           // ),
         ),
-        bottomNavigationBar: const BottomBar(),
-        drawer: const SideDrawer(),
+        bottomNavigationBar: BottomBar(
+          children: [
+            BottomNavigationBarItem(
+              label: 'back',
+              backgroundColor: Colors.white,
+              icon: IconButton(
+                onPressed: () => Navigator.of(context).pop(),
+                icon: const Icon(
+                  Icons.arrow_back,
+                  color: Colors.white,
+                ),
+              ),
+            ),
+            BottomNavigationBarItem(
+              backgroundColor: Colors.white,
+              label: 'Menu',
+              icon: IconButton(
+                onPressed: () => Scaffold.of(context).openDrawer(),
+                icon: const Icon(
+                  Icons.menu,
+                  color: Colors.white,
+                ),
+              ),
+            ),
+          ],
+        ),
+        drawer: SideDrawer(children: [
+          const Spacer(),
+          TextButton(
+            onPressed: () {
+              Scaffold.of(context).closeDrawer();
+            },
+            child: const Row(
+              children: [
+                Text(
+                  'About',
+                  style: TextStyle(fontSize: 20),
+                ),
+                Spacer(),
+                Icon(
+                  Icons.question_answer,
+                  color: Colors.white,
+                ),
+              ],
+            ),
+          ),
+          TextButton(
+            onPressed: () {
+              Scaffold.of(context).closeDrawer();
+            },
+            child: const Row(
+              children: [
+                Text(
+                  'Datenschutz',
+                  style: TextStyle(fontSize: 20),
+                ),
+                Spacer(),
+                Icon(
+                  Icons.privacy_tip,
+                  color: Colors.white,
+                ),
+              ],
+            ),
+          ),
+          TextButton(
+            onPressed: () {
+              Scaffold.of(context).closeDrawer();
+            },
+            child: const Row(
+              children: [
+                Text(
+                  'Impressum',
+                  style: TextStyle(fontSize: 20),
+                ),
+                Spacer(),
+                Icon(
+                  Icons.apartment,
+                  color: Colors.white,
+                ),
+              ],
+            ),
+          ),
+          const SizedBox(
+            height: 250,
+          )
+        ]),
         body: !_loading
             ? Form(
                 key: _formKey,
@@ -256,121 +342,3 @@ class _LoginPageState extends State<LoginPage> {
     );
   }
 }
-
-class SideDrawer extends StatelessWidget {
-  const SideDrawer({
-    super.key,
-  });
-
-  @override
-  Widget build(BuildContext context) {
-    return Drawer(
-      backgroundColor: Colors.black,
-      child: Padding(
-        padding: const EdgeInsets.all(40.0),
-        child: Column(
-          mainAxisAlignment: MainAxisAlignment.center,
-          children: [
-            const Spacer(),
-            TextButton(
-              onPressed: () {
-                Scaffold.of(context).closeDrawer();
-              },
-              child: const Row(
-                children: [
-                  Text(
-                    'About',
-                    style: TextStyle(fontSize: 20),
-                  ),
-                  Spacer(),
-                  Icon(
-                    Icons.question_answer,
-                    color: Colors.white,
-                  ),
-                ],
-              ),
-            ),
-            TextButton(
-              onPressed: () {
-                Scaffold.of(context).closeDrawer();
-              },
-              child: const Row(
-                children: [
-                  Text(
-                    'Datenschutz',
-                    style: TextStyle(fontSize: 20),
-                  ),
-                  Spacer(),
-                  Icon(
-                    Icons.privacy_tip,
-                    color: Colors.white,
-                  ),
-                ],
-              ),
-            ),
-            TextButton(
-              onPressed: () {
-                Scaffold.of(context).closeDrawer();
-              },
-              child: const Row(
-                children: [
-                  Text(
-                    'Impressum',
-                    style: TextStyle(fontSize: 20),
-                  ),
-                  Spacer(),
-                  Icon(
-                    Icons.apartment,
-                    color: Colors.white,
-                  ),
-                ],
-              ),
-            ),
-            const SizedBox(
-              height: 250,
-            )
-          ],
-        ),
-      ),
-    );
-  }
-}
-
-class BottomBar extends StatelessWidget {
-  const BottomBar({
-    super.key,
-  });
-
-  @override
-  Widget build(BuildContext context) {
-    return BottomNavigationBar(
-      items: [
-        BottomNavigationBarItem(
-          label: 'back',
-          backgroundColor: Colors.white,
-          icon: IconButton(
-            onPressed: () => Navigator.of(context).pop(),
-            icon: const Icon(
-              Icons.arrow_back,
-              color: Colors.white,
-            ),
-          ),
-        ),
-        BottomNavigationBarItem(
-          backgroundColor: Colors.white,
-          label: 'Menu',
-          icon: IconButton(
-            onPressed: () => Scaffold.of(context).openDrawer(),
-            icon: const Icon(
-              Icons.menu,
-              color: Colors.white,
-            ),
-          ),
-        ),
-      ],
-      backgroundColor: Colors.black,
-      fixedColor: Colors.black,
-      // onTap: (value) => _bottomBarAction(value),
-    );
-  }
-}
diff --git a/frontend/app/lib/pages/start_page.dart b/frontend/app/lib/pages/start_page.dart
index b106f3b..e3f2ba9 100644
--- a/frontend/app/lib/pages/start_page.dart
+++ b/frontend/app/lib/pages/start_page.dart
@@ -1,6 +1,8 @@
 import 'package:app/gapi/client.dart';
 import 'package:app/pages/login_page.dart';
 import 'package:app/widgets/background.dart';
+import 'package:app/widgets/bottom_bar.dart';
+import 'package:app/widgets/side_drawer.dart';
 import 'package:flutter/material.dart';
 import 'dart:core';
 
@@ -40,15 +42,194 @@ class _StartPageState extends State<StartPage> {
         appBar: AppBar(
           automaticallyImplyLeading: false,
         ),
-        drawer: SideDrawer(
-          onLogout: () {
-            setState(() {
-              widget.client?.session
-                  .removeSession(widget.client!.session.sessionId!);
-            });
-          },
-        ),
-        bottomNavigationBar: BottomBar(widget: widget),
+        drawer: SideDrawer(children: [
+          const Spacer(),
+          TextButton(
+            onPressed: () {
+              Scaffold.of(context).closeDrawer();
+            },
+            child: const Row(
+              children: [
+                Text(
+                  'About',
+                  style: TextStyle(fontSize: 20),
+                ),
+                Spacer(),
+                Icon(
+                  Icons.question_answer,
+                  color: Colors.white,
+                ),
+              ],
+            ),
+          ),
+          TextButton(
+            onPressed: () {
+              Scaffold.of(context).closeDrawer();
+            },
+            child: const Row(
+              children: [
+                Text(
+                  'Datenschutz',
+                  style: TextStyle(fontSize: 20),
+                ),
+                Spacer(),
+                Icon(
+                  Icons.privacy_tip,
+                  color: Colors.white,
+                ),
+              ],
+            ),
+          ),
+          TextButton(
+            onPressed: () {
+              Scaffold.of(context).closeDrawer();
+            },
+            child: const Row(
+              children: [
+                Text(
+                  'Impressum',
+                  style: TextStyle(fontSize: 20),
+                ),
+                Spacer(),
+                Icon(
+                  Icons.apartment,
+                  color: Colors.white,
+                ),
+              ],
+            ),
+          ),
+          TextButton(
+            onPressed: () {
+              setState(() {
+                widget.client?.session.accessToken = null;
+                widget.client?.session
+                    .removeSession(widget.client!.session.sessionId!);
+              });
+            },
+            child: const Row(
+              children: [
+                Text(
+                  'Log out',
+                  style: TextStyle(fontSize: 20),
+                ),
+                Spacer(),
+                Icon(
+                  Icons.logout,
+                  color: Colors.white,
+                ),
+              ],
+            ),
+          ),
+          const SizedBox(
+            height: 250,
+          )
+        ]),
+        bottomNavigationBar: Builder(builder: (context) {
+          return BottomBar(
+            // onTap: (value) => _bottomBarAction(value),
+            children: widget.client?.session.accessToken != null
+                ? [
+                    BottomNavigationBarItem(
+                      backgroundColor: Colors.white,
+                      label: 'Personen',
+                      icon: Column(
+                        children: [
+                          IconButton(
+                            onPressed: () => Scaffold.of(context).openDrawer(),
+                            icon: const Icon(
+                              Icons.group,
+                              color: Colors.white,
+                            ),
+                          ),
+                          const Text(
+                            'Personen',
+                            style: TextStyle(
+                              color: Colors.white,
+                              fontSize: 16,
+                            ),
+                          )
+                        ],
+                      ),
+                    ),
+                    BottomNavigationBarItem(
+                      backgroundColor: Colors.white,
+                      label: 'Menu',
+                      icon: IconButton(
+                        onPressed: () {
+                          Scaffold.of(context).openDrawer();
+                        },
+                        icon: const Icon(
+                          Icons.menu,
+                          color: Colors.white,
+                        ),
+                      ),
+                    )
+                  ]
+                : [
+                    BottomNavigationBarItem(
+                      label: 'register',
+                      backgroundColor: Colors.white,
+                      icon: Column(
+                        children: [
+                          IconButton(
+                            onPressed: () {
+                              Navigator.of(context).push(MaterialPageRoute(
+                                  builder: (context) => LoginPage()));
+                            },
+                            icon: const Icon(
+                              Icons.login,
+                              color: Colors.white,
+                            ),
+                          ),
+                          const Text(
+                            'Registrieren',
+                            style: TextStyle(
+                              color: Colors.white,
+                              fontSize: 16,
+                            ),
+                          )
+                        ],
+                      ),
+                    ),
+                    BottomNavigationBarItem(
+                      label: 'login',
+                      backgroundColor: Colors.white,
+                      icon: Column(
+                        children: [
+                          IconButton(
+                            onPressed: () {
+                              Navigator.of(context).push(MaterialPageRoute(
+                                  builder: (context) => LoginPage()));
+                            },
+                            icon: const Icon(
+                              Icons.login,
+                              color: Colors.white,
+                            ),
+                          ),
+                          const Text(
+                            'Login',
+                            style: TextStyle(
+                              color: Colors.white,
+                              fontSize: 16,
+                            ),
+                          )
+                        ],
+                      ),
+                    ),
+                    BottomNavigationBarItem(
+                      backgroundColor: Colors.white,
+                      label: 'Menu',
+                      icon: IconButton(
+                        onPressed: () => Scaffold.of(context).openDrawer(),
+                        icon: const Icon(
+                          Icons.menu,
+                          color: Colors.white,
+                        ),
+                      ),
+                    ),
+                  ],
+          );
+        }),
         body: Padding(
           padding: const EdgeInsets.all(16.0),
           child: Column(
@@ -74,54 +255,14 @@ class _StartPageState extends State<StartPage> {
                 ),
               ),
               TextButton(
-                onPressed: () {
-                  final s = widget.client?.session.getSessions();
-                  print(s);
-                  print(widget.client?.session.accessToken);
+                onPressed: () async {
+                  final s = await widget.client?.session.getSessions();
+                  print('SESSIONS: $s');
                 },
                 child: const Text(
                   "GET SESSIONS",
                 ),
               ),
-              // const Spacer(),
-              // Row(
-              //   mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-              //   crossAxisAlignment: CrossAxisAlignment.center,
-              //   children: widget.client?.accessToken == null
-              //       ? [
-              // ElevatedButton.icon(
-              //   label: const Text('Login'),
-              //   onPressed: () {
-              //     // onChangePage(Pages.login);
-              //     Navigator.of(context).push(
-              //       MaterialPageRoute(
-              //         builder: ((context) => LoginPage()),
-              //       ),
-              //     );
-              //   },
-              //   icon: const Icon(
-              //     Icons.login,
-              //     semanticLabel: 'Login',
-              //     size: 16,
-              //   ),
-              // ),
-              //   ElevatedButton.icon(
-              //     label: const Text('Registrieren'),
-              //     onPressed: () {},
-              //     icon: const Icon(
-              //       Icons.person_add,
-              //       semanticLabel: 'Register',
-              //       size: 16,
-              //     ),
-              //   ),
-              // ]
-              // : [],
-              // ),
-              // const SizedBox(
-              //   height: 38,
-              // ),
-
-              // const Text('data'),
             ],
           ),
         ),
@@ -129,220 +270,3 @@ class _StartPageState extends State<StartPage> {
     );
   }
 }
-
-class SideDrawer extends StatelessWidget {
-  SideDrawer({
-    super.key,
-    required this.onLogout,
-  });
-
-  Function() onLogout;
-
-  @override
-  Widget build(BuildContext context) {
-    return Drawer(
-      backgroundColor: Colors.black,
-      child: Padding(
-        padding: const EdgeInsets.all(40.0),
-        child: Column(
-          mainAxisAlignment: MainAxisAlignment.center,
-          children: [
-            const Spacer(),
-            TextButton(
-              onPressed: () {
-                Scaffold.of(context).closeDrawer();
-              },
-              child: const Row(
-                children: [
-                  Text(
-                    'About',
-                    style: TextStyle(fontSize: 20),
-                  ),
-                  Spacer(),
-                  Icon(
-                    Icons.question_answer,
-                    color: Colors.white,
-                  ),
-                ],
-              ),
-            ),
-            TextButton(
-              onPressed: () {
-                Scaffold.of(context).closeDrawer();
-              },
-              child: const Row(
-                children: [
-                  Text(
-                    'Datenschutz',
-                    style: TextStyle(fontSize: 20),
-                  ),
-                  Spacer(),
-                  Icon(
-                    Icons.privacy_tip,
-                    color: Colors.white,
-                  ),
-                ],
-              ),
-            ),
-            TextButton(
-              onPressed: () {
-                Scaffold.of(context).closeDrawer();
-              },
-              child: const Row(
-                children: [
-                  Text(
-                    'Impressum',
-                    style: TextStyle(fontSize: 20),
-                  ),
-                  Spacer(),
-                  Icon(
-                    Icons.apartment,
-                    color: Colors.white,
-                  ),
-                ],
-              ),
-            ),
-            TextButton(
-              onPressed: () {
-                onLogout();
-              },
-              child: const Row(
-                children: [
-                  Text(
-                    'Log out',
-                    style: TextStyle(fontSize: 20),
-                  ),
-                  Spacer(),
-                  Icon(
-                    Icons.logout,
-                    color: Colors.white,
-                  ),
-                ],
-              ),
-            ),
-            const SizedBox(
-              height: 250,
-            )
-          ],
-        ),
-      ),
-    );
-  }
-}
-
-class BottomBar extends StatelessWidget {
-  const BottomBar({
-    super.key,
-    required this.widget,
-  });
-
-  final StartPage widget;
-
-  @override
-  Widget build(BuildContext context) {
-    return BottomNavigationBar(
-      // onTap: (value) => _bottomBarAction(value),
-      items: widget.client?.session.accessToken != null
-          ? [
-              BottomNavigationBarItem(
-                backgroundColor: Colors.white,
-                label: 'Personen',
-                icon: Column(
-                  children: [
-                    IconButton(
-                      onPressed: () => Scaffold.of(context).openDrawer(),
-                      icon: const Icon(
-                        Icons.group,
-                        color: Colors.white,
-                      ),
-                    ),
-                    const Text(
-                      'Personen',
-                      style: TextStyle(
-                        color: Colors.white,
-                        fontSize: 16,
-                      ),
-                    )
-                  ],
-                ),
-              ),
-              BottomNavigationBarItem(
-                backgroundColor: Colors.white,
-                label: 'Menu',
-                icon: IconButton(
-                  onPressed: () => Scaffold.of(context).openDrawer(),
-                  icon: const Icon(
-                    Icons.menu,
-                    color: Colors.white,
-                  ),
-                ),
-              )
-            ]
-          : [
-              BottomNavigationBarItem(
-                label: 'register',
-                backgroundColor: Colors.white,
-                icon: Column(
-                  children: [
-                    IconButton(
-                      onPressed: () {
-                        Navigator.of(context).push(MaterialPageRoute(
-                            builder: (context) => LoginPage()));
-                      },
-                      icon: const Icon(
-                        Icons.login,
-                        color: Colors.white,
-                      ),
-                    ),
-                    const Text(
-                      'Registrieren',
-                      style: TextStyle(
-                        color: Colors.white,
-                        fontSize: 16,
-                      ),
-                    )
-                  ],
-                ),
-              ),
-              BottomNavigationBarItem(
-                label: 'login',
-                backgroundColor: Colors.white,
-                icon: Column(
-                  children: [
-                    IconButton(
-                      onPressed: () {
-                        Navigator.of(context).push(MaterialPageRoute(
-                            builder: (context) => LoginPage()));
-                      },
-                      icon: const Icon(
-                        Icons.login,
-                        color: Colors.white,
-                      ),
-                    ),
-                    const Text(
-                      'Login',
-                      style: TextStyle(
-                        color: Colors.white,
-                        fontSize: 16,
-                      ),
-                    )
-                  ],
-                ),
-              ),
-              BottomNavigationBarItem(
-                backgroundColor: Colors.white,
-                label: 'Menu',
-                icon: IconButton(
-                  onPressed: () => Scaffold.of(context).openDrawer(),
-                  icon: const Icon(
-                    Icons.menu,
-                    color: Colors.white,
-                  ),
-                ),
-              ),
-            ],
-      backgroundColor: Colors.black,
-      fixedColor: Colors.black,
-    );
-  }
-}
diff --git a/frontend/app/lib/widgets/bottom_bar.dart b/frontend/app/lib/widgets/bottom_bar.dart
new file mode 100644
index 0000000..eb9a437
--- /dev/null
+++ b/frontend/app/lib/widgets/bottom_bar.dart
@@ -0,0 +1,20 @@
+import 'package:flutter/material.dart';
+
+class BottomBar extends StatelessWidget {
+  const BottomBar({
+    super.key,
+    required this.children,
+  });
+
+  final List<BottomNavigationBarItem> children;
+
+  @override
+  Widget build(BuildContext context) {
+    return BottomNavigationBar(
+      items: children,
+      backgroundColor: Colors.black,
+      fixedColor: Colors.black,
+      // onTap: (value) => _bottomBarAction(value),
+    );
+  }
+}
diff --git a/frontend/app/lib/widgets/side_drawer.dart b/frontend/app/lib/widgets/side_drawer.dart
new file mode 100644
index 0000000..73f55e2
--- /dev/null
+++ b/frontend/app/lib/widgets/side_drawer.dart
@@ -0,0 +1,29 @@
+import 'package:flutter/material.dart';
+
+class SideDrawer extends StatefulWidget {
+  const SideDrawer({
+    super.key,
+    required this.children,
+  });
+
+  final List<Widget> children;
+
+  @override
+  State<SideDrawer> createState() => _SideDrawerState();
+}
+
+class _SideDrawerState extends State<SideDrawer> {
+  @override
+  Widget build(BuildContext context) {
+    return Drawer(
+      backgroundColor: Colors.black,
+      child: Padding(
+        padding: const EdgeInsets.all(40.0),
+        child: Column(
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: widget.children,
+        ),
+      ),
+    );
+  }
+}

From ab09c558d8550a01dc05e8fe80c2333cff074fcb Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Tue, 31 Oct 2023 00:13:26 +0100
Subject: [PATCH 14/24] ft/adds dashboard_page and bugfixes

---
 frontend/app/lib/gapi/client.dart          |   8 +-
 frontend/app/lib/main.dart                 |   5 +-
 frontend/app/lib/pages/dashboard_page.dart | 237 +++++++++++++++++----
 frontend/app/lib/pages/login_page.dart     |   4 +-
 frontend/app/lib/pages/start_page.dart     | 217 +++++++++++--------
 5 files changed, 337 insertions(+), 134 deletions(-)

diff --git a/frontend/app/lib/gapi/client.dart b/frontend/app/lib/gapi/client.dart
index aae5a46..3ec591a 100644
--- a/frontend/app/lib/gapi/client.dart
+++ b/frontend/app/lib/gapi/client.dart
@@ -23,7 +23,9 @@ class GClient {
     GClient c = GClient();
     c.session = s;
     final sessions = await c.session.getSessions();
-    c.session = sessions[0];
+    if (sessions.isNotEmpty) {
+      c.session = sessions[0];
+    }
     return c;
   }
 
@@ -43,7 +45,9 @@ class GClient {
     session = await Session.newSession;
 
     final sessions = await session.getSessions();
-    session = sessions[0];
+    if (sessions.isNotEmpty) {
+      session = sessions[0];
+    }
   }
 
   Future<CreateAccountResponse> createAccount(
diff --git a/frontend/app/lib/main.dart b/frontend/app/lib/main.dart
index 78e9a9a..8e44a71 100644
--- a/frontend/app/lib/main.dart
+++ b/frontend/app/lib/main.dart
@@ -1,3 +1,4 @@
+import 'package:app/gapi/client.dart';
 import 'package:app/pages/start_page.dart';
 import 'package:app/widgets/background.dart';
 import 'package:flutter/material.dart';
@@ -43,7 +44,9 @@ void main() async {
             foregroundColor: Colors.white,
           )),
       home: Background(
-        child: StartPage(),
+        child: StartPage(
+          client: await GClient.client,
+        ),
       ),
     ),
   );
diff --git a/frontend/app/lib/pages/dashboard_page.dart b/frontend/app/lib/pages/dashboard_page.dart
index 6db7ed0..7279de4 100644
--- a/frontend/app/lib/pages/dashboard_page.dart
+++ b/frontend/app/lib/pages/dashboard_page.dart
@@ -1,12 +1,18 @@
 import 'package:app/gapi/client.dart';
+import 'package:app/pages/start_page.dart';
 import 'package:app/pb/account_info.pb.dart';
 import 'package:app/pb/rpc_get_account_info.pb.dart';
 import 'package:app/widgets/background.dart';
+import 'package:app/widgets/bottom_bar.dart';
 import 'package:app/widgets/loading_widget.dart';
+import 'package:app/widgets/side_drawer.dart';
 import 'package:flutter/material.dart';
 
 class DashboardPage extends StatefulWidget {
-  const DashboardPage({super.key, required this.client});
+  const DashboardPage({
+    super.key,
+    required this.client,
+  });
 
   final GClient client;
 
@@ -27,10 +33,6 @@ class _DashboardPageState extends State<DashboardPage> {
   @override
   void initState() {
     super.initState();
-    // if (widget.client.session.accessToken == '') {
-    //   Navigator.of(context).pop();
-    //   return;
-    // }
 
     _setLoading(true);
     widget.client.getAccountInfo(
@@ -59,7 +61,193 @@ class _DashboardPageState extends State<DashboardPage> {
             height: 80,
           ),
         ),
-        bottomNavigationBar: BottomBar(),
+        drawer: Builder(builder: (context) {
+          return SideDrawer(
+            children: [
+              const Spacer(),
+              TextButton(
+                onPressed: () {
+                  Scaffold.of(context).closeDrawer();
+                },
+                child: const Row(
+                  children: [
+                    Text(
+                      'About',
+                      style: TextStyle(fontSize: 20),
+                    ),
+                    Spacer(),
+                    Icon(
+                      Icons.question_answer,
+                      color: Colors.white,
+                    ),
+                  ],
+                ),
+              ),
+              TextButton(
+                onPressed: () {
+                  Scaffold.of(context).closeDrawer();
+                },
+                child: const Row(
+                  children: [
+                    Text(
+                      'Datenschutz',
+                      style: TextStyle(fontSize: 20),
+                    ),
+                    Spacer(),
+                    Icon(
+                      Icons.privacy_tip,
+                      color: Colors.white,
+                    ),
+                  ],
+                ),
+              ),
+              TextButton(
+                onPressed: () {
+                  Scaffold.of(context).closeDrawer();
+                },
+                child: const Row(
+                  children: [
+                    Text(
+                      'Impressum',
+                      style: TextStyle(fontSize: 20),
+                    ),
+                    Spacer(),
+                    Icon(
+                      Icons.apartment,
+                      color: Colors.white,
+                    ),
+                  ],
+                ),
+              ),
+              if (widget.client.session.accessToken != null)
+                TextButton(
+                  onPressed: () {
+                    widget.client.session.accessToken = null;
+                    widget.client.session
+                        .removeSession(widget.client.session.sessionId!);
+
+                    Navigator.of(context).pop(widget.client);
+                  },
+                  child: const Row(
+                    children: [
+                      Text(
+                        'Log out',
+                        style: TextStyle(fontSize: 20),
+                      ),
+                      Spacer(),
+                      Icon(
+                        Icons.logout,
+                        color: Colors.white,
+                      ),
+                    ],
+                  ),
+                ),
+              const SizedBox(
+                height: 250,
+              )
+            ],
+          );
+        }),
+        bottomNavigationBar: Builder(
+          builder: (context) {
+            return BottomBar(
+              children: widget.client.session.accessToken != null
+                  ? [
+                      BottomNavigationBarItem(
+                        backgroundColor: Colors.white,
+                        label: 'Personen',
+                        icon: Column(
+                          children: [
+                            IconButton(
+                              onPressed: () =>
+                                  Scaffold.of(context).openDrawer(),
+                              icon: const Icon(
+                                Icons.group,
+                                color: Colors.white,
+                              ),
+                            ),
+                            const Text(
+                              'Personen',
+                              style: TextStyle(
+                                color: Colors.white,
+                                fontSize: 16,
+                              ),
+                            )
+                          ],
+                        ),
+                      ),
+                      BottomNavigationBarItem(
+                        backgroundColor: Colors.white,
+                        label: 'Home',
+                        icon: Column(
+                          children: [
+                            IconButton(
+                              onPressed: () {
+                                Navigator.of(context).push(
+                                  MaterialPageRoute(
+                                    builder: (context) => StartPage(
+                                      client: widget.client,
+                                    ),
+                                  ),
+                                );
+                              },
+                              icon: const Icon(
+                                Icons.home,
+                                color: Colors.white,
+                              ),
+                            ),
+                            const Text(
+                              'Home',
+                              style: TextStyle(
+                                color: Colors.white,
+                                fontSize: 16,
+                              ),
+                            )
+                          ],
+                        ),
+                      ),
+                      BottomNavigationBarItem(
+                        backgroundColor: Colors.white,
+                        label: 'Menu',
+                        icon: IconButton(
+                          onPressed: () {
+                            Scaffold.of(context).openDrawer();
+                          },
+                          icon: const Icon(
+                            Icons.menu,
+                            color: Colors.white,
+                          ),
+                        ),
+                      )
+                    ]
+                  : [
+                      BottomNavigationBarItem(
+                        label: 'back',
+                        backgroundColor: Colors.white,
+                        icon: IconButton(
+                          onPressed: () =>
+                              Navigator.of(context).pop(widget.client),
+                          icon: const Icon(
+                            Icons.arrow_back,
+                            color: Colors.white,
+                          ),
+                        ),
+                      ),
+                      BottomNavigationBarItem(
+                        backgroundColor: Colors.white,
+                        label: 'Menu',
+                        icon: IconButton(
+                          onPressed: () => Scaffold.of(context).openDrawer(),
+                          icon: const Icon(
+                            Icons.menu,
+                            color: Colors.white,
+                          ),
+                        ),
+                      ),
+                    ],
+            );
+          },
+        ),
         body: !_loading
             ? Background(
                 child: Center(
@@ -83,40 +271,3 @@ class _DashboardPageState extends State<DashboardPage> {
     );
   }
 }
-
-class BottomBar extends StatelessWidget {
-  const BottomBar({
-    super.key,
-  });
-
-  @override
-  Widget build(BuildContext context) {
-    return BottomNavigationBar(
-      items: [
-        BottomNavigationBarItem(
-          label: 'back',
-          backgroundColor: Colors.white,
-          icon: IconButton(
-            onPressed: () => Navigator.of(context).pop(),
-            icon: const Icon(
-              Icons.arrow_back,
-              color: Colors.white,
-            ),
-          ),
-        ),
-        BottomNavigationBarItem(
-          backgroundColor: Colors.white,
-          label: 'Menu',
-          icon: IconButton(
-            onPressed: () => Scaffold.of(context).openDrawer(),
-            icon: const Icon(
-              Icons.person,
-              color: Colors.white,
-            ),
-          ),
-        ),
-      ],
-      backgroundColor: Colors.black,
-    );
-  }
-}
diff --git a/frontend/app/lib/pages/login_page.dart b/frontend/app/lib/pages/login_page.dart
index 4856e08..26d7482 100644
--- a/frontend/app/lib/pages/login_page.dart
+++ b/frontend/app/lib/pages/login_page.dart
@@ -35,7 +35,7 @@ class _LoginPageState extends State<LoginPage> {
   void _bottomBarAction(int index) {
     switch (bottombarButtons[index].label?.toLowerCase()) {
       case 'back':
-        Navigator.of(context).pop();
+        Navigator.of(context).pop(client);
     }
   }
 
@@ -92,7 +92,7 @@ class _LoginPageState extends State<LoginPage> {
               label: 'back',
               backgroundColor: Colors.white,
               icon: IconButton(
-                onPressed: () => Navigator.of(context).pop(),
+                onPressed: () => Navigator.of(context).pop(client),
                 icon: const Icon(
                   Icons.arrow_back,
                   color: Colors.white,
diff --git a/frontend/app/lib/pages/start_page.dart b/frontend/app/lib/pages/start_page.dart
index e3f2ba9..c4f76db 100644
--- a/frontend/app/lib/pages/start_page.dart
+++ b/frontend/app/lib/pages/start_page.dart
@@ -1,4 +1,5 @@
 import 'package:app/gapi/client.dart';
+import 'package:app/pages/dashboard_page.dart';
 import 'package:app/pages/login_page.dart';
 import 'package:app/widgets/background.dart';
 import 'package:app/widgets/bottom_bar.dart';
@@ -9,10 +10,10 @@ import 'dart:core';
 class StartPage extends StatefulWidget {
   StartPage({
     super.key,
-    this.client,
+    required this.client,
   });
 
-  GClient? client;
+  GClient client;
 
   @override
   State<StartPage> createState() => _StartPageState();
@@ -42,88 +43,90 @@ class _StartPageState extends State<StartPage> {
         appBar: AppBar(
           automaticallyImplyLeading: false,
         ),
-        drawer: SideDrawer(children: [
-          const Spacer(),
-          TextButton(
-            onPressed: () {
-              Scaffold.of(context).closeDrawer();
-            },
-            child: const Row(
-              children: [
-                Text(
-                  'About',
-                  style: TextStyle(fontSize: 20),
-                ),
-                Spacer(),
-                Icon(
-                  Icons.question_answer,
-                  color: Colors.white,
-                ),
-              ],
+        drawer: Builder(builder: (context) {
+          return SideDrawer(children: [
+            const Spacer(),
+            TextButton(
+              onPressed: () {
+                Scaffold.of(context).closeDrawer();
+              },
+              child: const Row(
+                children: [
+                  Text(
+                    'About',
+                    style: TextStyle(fontSize: 20),
+                  ),
+                  Spacer(),
+                  Icon(
+                    Icons.question_answer,
+                    color: Colors.white,
+                  ),
+                ],
+              ),
             ),
-          ),
-          TextButton(
-            onPressed: () {
-              Scaffold.of(context).closeDrawer();
-            },
-            child: const Row(
-              children: [
-                Text(
-                  'Datenschutz',
-                  style: TextStyle(fontSize: 20),
-                ),
-                Spacer(),
-                Icon(
-                  Icons.privacy_tip,
-                  color: Colors.white,
-                ),
-              ],
+            TextButton(
+              onPressed: () {
+                Scaffold.of(context).closeDrawer();
+              },
+              child: const Row(
+                children: [
+                  Text(
+                    'Datenschutz',
+                    style: TextStyle(fontSize: 20),
+                  ),
+                  Spacer(),
+                  Icon(
+                    Icons.privacy_tip,
+                    color: Colors.white,
+                  ),
+                ],
+              ),
             ),
-          ),
-          TextButton(
-            onPressed: () {
-              Scaffold.of(context).closeDrawer();
-            },
-            child: const Row(
-              children: [
-                Text(
-                  'Impressum',
-                  style: TextStyle(fontSize: 20),
-                ),
-                Spacer(),
-                Icon(
-                  Icons.apartment,
-                  color: Colors.white,
-                ),
-              ],
+            TextButton(
+              onPressed: () {
+                Scaffold.of(context).closeDrawer();
+              },
+              child: const Row(
+                children: [
+                  Text(
+                    'Impressum',
+                    style: TextStyle(fontSize: 20),
+                  ),
+                  Spacer(),
+                  Icon(
+                    Icons.apartment,
+                    color: Colors.white,
+                  ),
+                ],
+              ),
             ),
-          ),
-          TextButton(
-            onPressed: () {
-              setState(() {
-                widget.client?.session.accessToken = null;
-                widget.client?.session
-                    .removeSession(widget.client!.session.sessionId!);
-              });
-            },
-            child: const Row(
-              children: [
-                Text(
-                  'Log out',
-                  style: TextStyle(fontSize: 20),
-                ),
-                Spacer(),
-                Icon(
-                  Icons.logout,
-                  color: Colors.white,
-                ),
-              ],
+            TextButton(
+              onPressed: () {
+                setState(() {
+                  widget.client?.session.accessToken = null;
+                  widget.client?.session
+                      .removeSession(widget.client!.session.sessionId!);
+                });
+              },
+              child: const Row(
+                children: [
+                  Text(
+                    'Log out',
+                    style: TextStyle(fontSize: 20),
+                  ),
+                  Spacer(),
+                  Icon(
+                    Icons.logout,
+                    color: Colors.white,
+                  ),
+                ],
+              ),
             ),
-          ),
-          const SizedBox(
-            height: 250,
-          )
-        ]),
+            const SizedBox(
+              height: 250,
+            )
+          ]);
+        }),
         bottomNavigationBar: Builder(builder: (context) {
           return BottomBar(
             // onTap: (value) => _bottomBarAction(value),
@@ -151,6 +154,44 @@ class _StartPageState extends State<StartPage> {
                         ],
                       ),
                     ),
+                    BottomNavigationBarItem(
+                      backgroundColor: Colors.white,
+                      label: 'Dashboard',
+                      icon: Column(
+                        children: [
+                          IconButton(
+                            onPressed: () async {
+                              // setState(() {
+
+                              GClient c = await Navigator.push(
+                                context,
+                                MaterialPageRoute(
+                                  builder: (context) => DashboardPage(
+                                    client: widget.client!,
+                                  ),
+                                ),
+                              );
+                              print('Got Client back: $c');
+                              // });
+                              setState(() {
+                                widget.client = c;
+                              });
+                            },
+                            icon: const Icon(
+                              Icons.dashboard,
+                              color: Colors.white,
+                            ),
+                          ),
+                          const Text(
+                            'Dashboard',
+                            style: TextStyle(
+                              color: Colors.white,
+                              fontSize: 16,
+                            ),
+                          )
+                        ],
+                      ),
+                    ),
                     BottomNavigationBarItem(
                       backgroundColor: Colors.white,
                       label: 'Menu',
@@ -172,9 +213,11 @@ class _StartPageState extends State<StartPage> {
                       icon: Column(
                         children: [
                           IconButton(
-                            onPressed: () {
-                              Navigator.of(context).push(MaterialPageRoute(
-                                  builder: (context) => LoginPage()));
+                            onPressed: () async {
+                              widget.client = await Navigator.push(
+                                  context,
+                                  MaterialPageRoute(
+                                      builder: (context) => LoginPage()));
                             },
                             icon: const Icon(
                               Icons.login,
@@ -197,9 +240,11 @@ class _StartPageState extends State<StartPage> {
                       icon: Column(
                         children: [
                           IconButton(
-                            onPressed: () {
-                              Navigator.of(context).push(MaterialPageRoute(
-                                  builder: (context) => LoginPage()));
+                            onPressed: () async {
+                              widget.client = await Navigator.push(
+                                  context,
+                                  MaterialPageRoute(
+                                      builder: (context) => LoginPage()));
                             },
                             icon: const Icon(
                               Icons.login,

From 4887e0fd4dc1dbe2f843afe2e180bab76865d2f9 Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Tue, 31 Oct 2023 15:50:58 +0100
Subject: [PATCH 15/24] ft/adds register_page and some improvements

---
 frontend/app/lib/gapi/client.dart          |  66 ++++-
 frontend/app/lib/pages/dashboard_page.dart |  43 ++-
 frontend/app/lib/pages/login_page.dart     |  19 +-
 frontend/app/lib/pages/register_page.dart  | 301 +++++++++++++++++++++
 frontend/app/lib/pages/start_page.dart     |  80 +++---
 5 files changed, 446 insertions(+), 63 deletions(-)
 create mode 100644 frontend/app/lib/pages/register_page.dart

diff --git a/frontend/app/lib/gapi/client.dart b/frontend/app/lib/gapi/client.dart
index 3ec591a..eacc050 100644
--- a/frontend/app/lib/gapi/client.dart
+++ b/frontend/app/lib/gapi/client.dart
@@ -1,8 +1,8 @@
 import 'package:app/data/database.dart';
-import 'package:fixnum/fixnum.dart';
 import 'package:app/pb/rpc_create_account.pb.dart';
 import 'package:app/pb/rpc_get_account_info.pb.dart';
 import 'package:app/pb/rpc_login.pb.dart';
+import 'package:app/pb/rpc_refresh_token.pb.dart';
 import 'package:app/pb/service_df.pbgrpc.dart';
 import 'package:grpc/grpc.dart';
 
@@ -26,6 +26,7 @@ class GClient {
     if (sessions.isNotEmpty) {
       c.session = sessions[0];
     }
+    print('ACCESS_TOKEN: ${c.session.accessToken}');
     return c;
   }
 
@@ -51,11 +52,21 @@ class GClient {
   }
 
   Future<CreateAccountResponse> createAccount(
-      CreateAccountRequest request) async {
+      {required String email,
+      required String password,
+      required Function({GrpcError? error}) onError}) async {
     try {
-      final response = stub.createAccount(request);
+      final response = await stub.createAccount(CreateAccountRequest(
+        email: email,
+        password: password,
+      ));
       return response;
-    } catch (e) {}
+    } on GrpcError catch (e) {
+      onError(error: e);
+      print('GRPC ERROR: ${e.message}');
+    } catch (e) {
+      print('ERROR: $e');
+    }
     return CreateAccountResponse();
   }
 
@@ -94,23 +105,56 @@ class GClient {
     return response;
   }
 
-  Future<GetAccountInfoResponse> getAccountInfo(GetAccountInfoRequest request,
-      {required Function onError}) async {
+  bool get isLoggedIn =>
+      session.accessTokenExpiresAt != null &&
+      session.accessTokenExpiresAt!.toDateTime().isAfter(DateTime.now());
+
+  Future<void> resetSession() async {
+    if (session.sessionId != null) {
+      session.removeSession(session.sessionId!);
+    }
+    session = await Session.newSession;
+  }
+
+  Future<bool> refreshToken() async {
     try {
-      final response = await stub.getAccountInfo(
+      final response = await stub.refreshToken(
+        RefreshTokenRequest(
+          refreshToken: session.refreshToken,
+        ),
+      );
+      session.accessToken = response.accessToken;
+      session.insertSession(session);
+      return true;
+    } on GrpcError catch (e) {
+      print('caught grpc error: $e');
+    }
+    return false;
+  }
+
+  Future<GetAccountInfoResponse> getAccountInfo(GetAccountInfoRequest request,
+      {required Function({String msg}) onError}) async {
+    GetAccountInfoResponse response = GetAccountInfoResponse();
+    try {
+      print('SENDING REQ: $request WITH $metadata');
+      response = await stub.getAccountInfo(
         request,
         options: CallOptions(
-          metadata: metadata,
+          metadata: {'Authorization': 'Bearer ${session.accessToken}'},
         ),
       );
       return response;
     } on GrpcError catch (e) {
-      print('caught error: ${e.message}');
-      onError();
+      print('caught grpc error: ${e.message} [${e.code}]');
+      if (e.code == 16) {
+        onError(msg: 'Sitzung ist abgelaufen.\nBitte loggen Sie sich neu ein.');
+      } else {
+        onError(msg: e.message != null ? e.message! : 'Interner Fehler');
+      }
     } catch (e) {
       print('caught error: $e');
       onError();
     }
-    return GetAccountInfoResponse();
+    return response;
   }
 }
diff --git a/frontend/app/lib/pages/dashboard_page.dart b/frontend/app/lib/pages/dashboard_page.dart
index 7279de4..6be86ba 100644
--- a/frontend/app/lib/pages/dashboard_page.dart
+++ b/frontend/app/lib/pages/dashboard_page.dart
@@ -39,10 +39,35 @@ class _DashboardPageState extends State<DashboardPage> {
       GetAccountInfoRequest(
         accountId: widget.client.session.accountId,
       ),
-      onError: () {
-        ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
-          content: Text('AccountInfo konnte nicht geladen werden'),
-        ));
+      onError: ({String? msg}) {
+        ScaffoldMessenger.of(context).showSnackBar(
+          SnackBar(
+            content: const Text('AccountInfo konnte nicht geladen werden'),
+            action: msg != null
+                ? SnackBarAction(
+                    label: 'Details',
+                    textColor: Colors.grey,
+                    onPressed: () {
+                      showDialog(
+                        context: context,
+                        builder: (context) {
+                          return AlertDialog(
+                            content: Text(
+                              msg,
+                              textAlign: TextAlign.center,
+                              style: const TextStyle(color: Colors.black),
+                            ),
+                            icon: const Icon(
+                              Icons.warning,
+                              color: Colors.red,
+                            ),
+                          );
+                        },
+                      );
+                    })
+                : null,
+          ),
+        );
       },
     ).then((value) {
       accountInfo = value.accountInfo;
@@ -126,7 +151,12 @@ class _DashboardPageState extends State<DashboardPage> {
                     widget.client.session
                         .removeSession(widget.client.session.sessionId!);
 
-                    Navigator.of(context).pop(widget.client);
+                    Navigator.of(context).pushAndRemoveUntil(
+                        MaterialPageRoute(
+                          builder: (context) =>
+                              StartPage(client: widget.client),
+                        ),
+                        (route) => false);
                   },
                   child: const Row(
                     children: [
@@ -225,8 +255,7 @@ class _DashboardPageState extends State<DashboardPage> {
                         label: 'back',
                         backgroundColor: Colors.white,
                         icon: IconButton(
-                          onPressed: () =>
-                              Navigator.of(context).pop(widget.client),
+                          onPressed: () {},
                           icon: const Icon(
                             Icons.arrow_back,
                             color: Colors.white,
diff --git a/frontend/app/lib/pages/login_page.dart b/frontend/app/lib/pages/login_page.dart
index 26d7482..daf5e9b 100644
--- a/frontend/app/lib/pages/login_page.dart
+++ b/frontend/app/lib/pages/login_page.dart
@@ -10,11 +10,13 @@ import 'package:grpc/grpc.dart';
 // GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
 
 class LoginPage extends StatefulWidget {
-  LoginPage({
+  const LoginPage({
     super.key,
+    required this.client,
     // required this.onChangePage,
   });
 
+  final GClient client;
   // void Function(Pages page) onChangePage;
 
   @override
@@ -32,13 +34,6 @@ class _LoginPageState extends State<LoginPage> {
     _addBottomBarButtons();
   }
 
-  void _bottomBarAction(int index) {
-    switch (bottombarButtons[index].label?.toLowerCase()) {
-      case 'back':
-        Navigator.of(context).pop(client);
-    }
-  }
-
   void _addBottomBarButtons() {
     bottombarButtons.addAll([
       const BottomNavigationBarItem(
@@ -69,7 +64,7 @@ class _LoginPageState extends State<LoginPage> {
     });
   }
 
-  final GClient client = GClient();
+  // final GClient client = GClient();
 
   final _formKey = GlobalKey<FormState>();
   final mailController = TextEditingController();
@@ -92,7 +87,7 @@ class _LoginPageState extends State<LoginPage> {
               label: 'back',
               backgroundColor: Colors.white,
               icon: IconButton(
-                onPressed: () => Navigator.of(context).pop(client),
+                onPressed: () => Navigator.of(context).pop(widget.client),
                 icon: const Icon(
                   Icons.arrow_back,
                   color: Colors.white,
@@ -255,7 +250,7 @@ class _LoginPageState extends State<LoginPage> {
                               if (_formKey.currentState!.validate()) {
                                 // final navigator = Navigator.of(context);
                                 _setLoading(true);
-                                client
+                                widget.client
                                     .login(
                                   email: mailController.text,
                                   password: passwordController.text,
@@ -317,7 +312,7 @@ class _LoginPageState extends State<LoginPage> {
                                         context,
                                         MaterialPageRoute(
                                           builder: (ctx) => StartPage(
-                                            client: client,
+                                            client: widget.client,
                                           ),
                                         ),
                                         (ctx) => false,
diff --git a/frontend/app/lib/pages/register_page.dart b/frontend/app/lib/pages/register_page.dart
new file mode 100644
index 0000000..923f72a
--- /dev/null
+++ b/frontend/app/lib/pages/register_page.dart
@@ -0,0 +1,301 @@
+import 'package:app/gapi/client.dart';
+import 'package:app/pages/start_page.dart';
+import 'package:app/widgets/background.dart';
+import 'package:app/widgets/bottom_bar.dart';
+import 'package:app/widgets/loading_widget.dart';
+import 'package:app/widgets/side_drawer.dart';
+import 'package:flutter/material.dart';
+import 'package:grpc/grpc.dart';
+
+class RegisterPage extends StatefulWidget {
+  const RegisterPage({
+    super.key,
+    required this.client,
+  });
+
+  final GClient client;
+
+  @override
+  State<RegisterPage> createState() => _RegisterPageState();
+}
+
+class _RegisterPageState extends State<RegisterPage> {
+  bool _loading = false;
+  final _formKey = GlobalKey<FormState>();
+  final mailController = TextEditingController();
+  final passwordController = TextEditingController();
+
+  void _setLoading(bool loading) {
+    setState(() {
+      _loading = loading;
+    });
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Background(
+      child: Scaffold(
+          appBar: AppBar(
+            automaticallyImplyLeading: false,
+            flexibleSpace: Image.asset(
+              'lib/assets/logo_300x200.png',
+              height: 80,
+            ),
+          ),
+          drawer: Builder(builder: (context) {
+            return SideDrawer(
+              children: [
+                const Spacer(),
+                TextButton(
+                  onPressed: () {
+                    Scaffold.of(context).closeDrawer();
+                  },
+                  child: const Row(
+                    children: [
+                      Text(
+                        'About',
+                        style: TextStyle(fontSize: 20),
+                      ),
+                      Spacer(),
+                      Icon(
+                        Icons.question_answer,
+                        color: Colors.white,
+                      ),
+                    ],
+                  ),
+                ),
+                TextButton(
+                  onPressed: () {
+                    Scaffold.of(context).closeDrawer();
+                  },
+                  child: const Row(
+                    children: [
+                      Text(
+                        'Datenschutz',
+                        style: TextStyle(fontSize: 20),
+                      ),
+                      Spacer(),
+                      Icon(
+                        Icons.privacy_tip,
+                        color: Colors.white,
+                      ),
+                    ],
+                  ),
+                ),
+                TextButton(
+                  onPressed: () {
+                    Scaffold.of(context).closeDrawer();
+                  },
+                  child: const Row(
+                    children: [
+                      Text(
+                        'Impressum',
+                        style: TextStyle(fontSize: 20),
+                      ),
+                      Spacer(),
+                      Icon(
+                        Icons.apartment,
+                        color: Colors.white,
+                      ),
+                    ],
+                  ),
+                ),
+                const SizedBox(
+                  height: 250,
+                )
+              ],
+            );
+          }),
+          bottomNavigationBar: BottomBar(
+            children: [
+              BottomNavigationBarItem(
+                label: 'back',
+                backgroundColor: Colors.white,
+                icon: IconButton(
+                  onPressed: () => Navigator.of(context).pop(widget.client),
+                  icon: const Icon(
+                    Icons.arrow_back,
+                    color: Colors.white,
+                  ),
+                ),
+              ),
+              BottomNavigationBarItem(
+                backgroundColor: Colors.white,
+                label: 'Menu',
+                icon: IconButton(
+                  onPressed: () => Scaffold.of(context).openDrawer(),
+                  icon: const Icon(
+                    Icons.menu,
+                    color: Colors.white,
+                  ),
+                ),
+              ),
+            ],
+          ),
+          body: !_loading
+              ? Form(
+                  key: _formKey,
+                  child: Padding(
+                    padding: const EdgeInsets.fromLTRB(16, 100, 16, 16),
+                    child: SingleChildScrollView(
+                      child: Column(
+                        crossAxisAlignment: CrossAxisAlignment.center,
+                        children: [
+                          const Image(
+                            width: 180,
+                            image: AssetImage(
+                              'lib/assets/logo_300x200.png',
+                            ),
+                          ),
+                          const SizedBox(
+                            height: 30,
+                          ),
+                          const Text(
+                            'Registrieren',
+                            style: TextStyle(
+                              fontFamily: 'sans-serif',
+                              fontSize: 24,
+                              height: 1.6,
+                              fontWeight: FontWeight.normal,
+                              letterSpacing: 6,
+                            ),
+                          ),
+                          const SizedBox(
+                            height: 20,
+                          ),
+                          TextFormField(
+                            controller: mailController,
+                            decoration: const InputDecoration(
+                              fillColor: Color.fromARGB(30, 255, 255, 255),
+                              filled: true,
+                              hintStyle: TextStyle(
+                                color: Colors.white38,
+                              ),
+                              hintText: 'E-Mail Adresse',
+                            ),
+                            keyboardType: TextInputType.emailAddress,
+                            validator: (value) {
+                              if (value == null || value.isEmpty) {
+                                return 'Bitte eine gültige E-Mail Adresse eingeben';
+                              }
+                              return null;
+                            },
+                          ),
+                          TextFormField(
+                            style: const TextStyle(
+                              color: Colors.white,
+                            ),
+                            controller: passwordController,
+                            decoration: const InputDecoration(
+                              fillColor: Color.fromARGB(30, 255, 255, 255),
+                              filled: true,
+                              hintStyle: TextStyle(
+                                color: Colors.white38,
+                              ),
+                              hintText: 'Passwort',
+                            ),
+                            keyboardType: TextInputType.visiblePassword,
+                            obscureText: true,
+                            validator: (value) {
+                              if (value == null || value.isEmpty) {
+                                return 'Bitte geben Sie Ihr Passwort ein';
+                              }
+                              return null;
+                            },
+                          ),
+                          const SizedBox(
+                            height: 15,
+                          ),
+                          ElevatedButton(
+                              onPressed: () {
+                                if (_formKey.currentState!.validate()) {
+                                  _setLoading(true);
+                                  widget.client
+                                      .createAccount(
+                                          email: mailController.text,
+                                          password: passwordController.text,
+                                          onError: ({GrpcError? error}) {
+                                            _setLoading(false);
+                                            ScaffoldMessenger.of(context)
+                                                .showSnackBar(SnackBar(
+                                              content: const Text(
+                                                'Login fehlgeschlagen',
+                                              ),
+                                              action: SnackBarAction(
+                                                  textColor: Colors.grey,
+                                                  label: 'Details',
+                                                  onPressed: () {
+                                                    showDialog(
+                                                      context: context,
+                                                      builder: (context) {
+                                                        return AlertDialog(
+                                                          content: error != null
+                                                              ? Text(
+                                                                  'Fehler: ${error.message}',
+                                                                  textAlign:
+                                                                      TextAlign
+                                                                          .center,
+                                                                  style: const TextStyle(
+                                                                      color: Colors
+                                                                          .black),
+                                                                )
+                                                              : const Text(
+                                                                  'Interner Fehler',
+                                                                  textAlign:
+                                                                      TextAlign
+                                                                          .center,
+                                                                  style: TextStyle(
+                                                                      color: Colors
+                                                                          .black),
+                                                                ),
+                                                          icon: const Icon(
+                                                            Icons.error,
+                                                            color: Colors.black,
+                                                          ),
+                                                        );
+                                                      },
+                                                    );
+                                                  }),
+                                            ));
+                                          })
+                                      .then(
+                                    (r) {
+                                      if (r.account.secretKey != '') {
+                                        Navigator.pushAndRemoveUntil(
+                                            context,
+                                            MaterialPageRoute(
+                                                builder: (builder) => StartPage(
+                                                    client: widget.client)),
+                                            (route) => false);
+                                        showDialog(
+                                            context: context,
+                                            builder: (builder) {
+                                              return const AlertDialog(
+                                                content: Text(
+                                                  'Account wurde angelegt',
+                                                  textAlign: TextAlign.center,
+                                                  style: TextStyle(
+                                                      color: Colors.black),
+                                                ),
+                                                icon: Icon(
+                                                  Icons.done,
+                                                  size: 50,
+                                                ),
+                                                iconColor: Colors.green,
+                                              );
+                                            });
+                                      }
+                                    },
+                                  );
+                                }
+                              },
+                              child: const Icon(Icons.login))
+                        ],
+                      ),
+                    ),
+                  ),
+                )
+              : const LoadingWidget()),
+    );
+  }
+}
diff --git a/frontend/app/lib/pages/start_page.dart b/frontend/app/lib/pages/start_page.dart
index c4f76db..bc4578b 100644
--- a/frontend/app/lib/pages/start_page.dart
+++ b/frontend/app/lib/pages/start_page.dart
@@ -1,12 +1,14 @@
 import 'package:app/gapi/client.dart';
 import 'package:app/pages/dashboard_page.dart';
 import 'package:app/pages/login_page.dart';
+import 'package:app/pages/register_page.dart';
 import 'package:app/widgets/background.dart';
 import 'package:app/widgets/bottom_bar.dart';
 import 'package:app/widgets/side_drawer.dart';
 import 'package:flutter/material.dart';
 import 'dart:core';
 
+// ignore: must_be_immutable
 class StartPage extends StatefulWidget {
   StartPage({
     super.key,
@@ -23,16 +25,23 @@ class _StartPageState extends State<StartPage> {
   // List<BottomNavigationBarItem> _selectedBottomBarButtons = bottomBarButtons;
   final List<BottomNavigationBarItem> bottombarButtons = [];
 
-  void _init() async {
-    final c = await GClient.client;
+  // void _init() async {
+  //   final c = await GClient.client;
+  //   setState(() {
+  //     widget.client = c;
+  //   });
+  // }
+
+  void _updateClient(GClient c) {
     setState(() {
+      print('GOT CLIENT: $c');
       widget.client = c;
     });
   }
 
   @override
   void initState() {
-    _init();
+    // _init();
     super.initState();
   }
 
@@ -103,9 +112,9 @@ class _StartPageState extends State<StartPage> {
             TextButton(
               onPressed: () {
                 setState(() {
-                  widget.client?.session.accessToken = null;
-                  widget.client?.session
-                      .removeSession(widget.client!.session.sessionId!);
+                  widget.client.session.accessToken = null;
+                  widget.client.session
+                      .removeSession(widget.client.session.sessionId!);
                 });
               },
               child: const Row(
@@ -130,7 +139,7 @@ class _StartPageState extends State<StartPage> {
         bottomNavigationBar: Builder(builder: (context) {
           return BottomBar(
             // onTap: (value) => _bottomBarAction(value),
-            children: widget.client?.session.accessToken != null
+            children: widget.client.session.accessToken != null
                 ? [
                     BottomNavigationBarItem(
                       backgroundColor: Colors.white,
@@ -161,21 +170,29 @@ class _StartPageState extends State<StartPage> {
                         children: [
                           IconButton(
                             onPressed: () async {
-                              // setState(() {
-
-                              GClient c = await Navigator.push(
-                                context,
-                                MaterialPageRoute(
-                                  builder: (context) => DashboardPage(
-                                    client: widget.client!,
+                              if (!widget.client.isLoggedIn) {
+                                ScaffoldMessenger.of(context).showSnackBar(
+                                  const SnackBar(
+                                    content: Text('Sitzung ist abgelaufen.'),
                                   ),
-                                ),
-                              );
-                              print('Got Client back: $c');
-                              // });
-                              setState(() {
-                                widget.client = c;
-                              });
+                                );
+                                Navigator.pushAndRemoveUntil(
+                                    context,
+                                    MaterialPageRoute(
+                                        builder: (context) =>
+                                            LoginPage(client: widget.client)),
+                                    (route) => false);
+                              } else {
+                                GClient c = await Navigator.push(
+                                  context,
+                                  MaterialPageRoute(
+                                    builder: (context) => DashboardPage(
+                                      client: widget.client,
+                                    ),
+                                  ),
+                                );
+                                _updateClient(c);
+                              }
                             },
                             icon: const Icon(
                               Icons.dashboard,
@@ -217,7 +234,9 @@ class _StartPageState extends State<StartPage> {
                               widget.client = await Navigator.push(
                                   context,
                                   MaterialPageRoute(
-                                      builder: (context) => LoginPage()));
+                                      builder: (context) => RegisterPage(
+                                            client: widget.client,
+                                          )));
                             },
                             icon: const Icon(
                               Icons.login,
@@ -241,10 +260,14 @@ class _StartPageState extends State<StartPage> {
                         children: [
                           IconButton(
                             onPressed: () async {
-                              widget.client = await Navigator.push(
+                              final c = await Navigator.push(
                                   context,
                                   MaterialPageRoute(
-                                      builder: (context) => LoginPage()));
+                                    builder: (context) => LoginPage(
+                                      client: widget.client,
+                                    ),
+                                  ));
+                              _updateClient(c);
                             },
                             icon: const Icon(
                               Icons.login,
@@ -299,15 +322,6 @@ class _StartPageState extends State<StartPage> {
                   letterSpacing: 6,
                 ),
               ),
-              TextButton(
-                onPressed: () async {
-                  final s = await widget.client?.session.getSessions();
-                  print('SESSIONS: $s');
-                },
-                child: const Text(
-                  "GET SESSIONS",
-                ),
-              ),
             ],
           ),
         ),

From b7a189e4090eea7454b5095db57b346993dbecf9 Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Tue, 31 Oct 2023 23:00:21 +0100
Subject: [PATCH 16/24] ft/adds session reset and client.account

---
 frontend/app/lib/data/database.dart | 13 ++++++++++++-
 frontend/app/lib/gapi/client.dart   | 14 ++++++++------
 2 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/frontend/app/lib/data/database.dart b/frontend/app/lib/data/database.dart
index f5d42d8..9cf0335 100644
--- a/frontend/app/lib/data/database.dart
+++ b/frontend/app/lib/data/database.dart
@@ -28,7 +28,7 @@ class Session {
 
   Future<Database> get database async => _database;
 
-  static Future<Session> get newSession async {
+  static Future<Session> get session async {
     final Database db = await openDatabase(
       join(await getDatabasesPath(), 'df_database.db'),
       onCreate: (db, version) {
@@ -47,6 +47,17 @@ class Session {
     _initDatabase();
   }
 
+  void reset() {
+    if (sessionId != null) {
+      removeSession(sessionId!);
+    }
+    sessionId = null;
+    accessToken = null;
+    refreshToken = null;
+    accessTokenExpiresAt = null;
+    refreshTokenExpiresAt = null;
+  }
+
   Future<Database> _initDatabase() async {
     // print('DB: INITIALIZING - start');
     _database = await openDatabase(
diff --git a/frontend/app/lib/gapi/client.dart b/frontend/app/lib/gapi/client.dart
index eacc050..b52a466 100644
--- a/frontend/app/lib/gapi/client.dart
+++ b/frontend/app/lib/gapi/client.dart
@@ -1,4 +1,5 @@
 import 'package:app/data/database.dart';
+import 'package:app/pb/account.pb.dart';
 import 'package:app/pb/rpc_create_account.pb.dart';
 import 'package:app/pb/rpc_get_account_info.pb.dart';
 import 'package:app/pb/rpc_login.pb.dart';
@@ -17,9 +18,10 @@ class GClient {
   Map<String, String> metadata = {'Authorization': ''};
 
   late Session session;
+  late Account account;
 
   static Future<GClient> get client async {
-    Session s = await Session.newSession;
+    Session s = await Session.session;
     GClient c = GClient();
     c.session = s;
     final sessions = await c.session.getSessions();
@@ -43,7 +45,7 @@ class GClient {
   Future<void> main(List<String> args) async {}
 
   void _init() async {
-    session = await Session.newSession;
+    session = await Session.session;
 
     final sessions = await session.getSessions();
     if (sessions.isNotEmpty) {
@@ -60,6 +62,7 @@ class GClient {
         email: email,
         password: password,
       ));
+      account = response.account;
       return response;
     } on GrpcError catch (e) {
       onError(error: e);
@@ -110,10 +113,9 @@ class GClient {
       session.accessTokenExpiresAt!.toDateTime().isAfter(DateTime.now());
 
   Future<void> resetSession() async {
-    if (session.sessionId != null) {
-      session.removeSession(session.sessionId!);
-    }
-    session = await Session.newSession;
+    session.reset();
+    account = Account();
+    session = await Session.session;
   }
 
   Future<bool> refreshToken() async {

From 496b81a5f55bed4b2fd214c85bda51ea4f4ba660 Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Wed, 1 Nov 2023 00:12:31 +0100
Subject: [PATCH 17/24] ft/adds autologin after register

---
 frontend/app/lib/gapi/client.dart         | 68 ++++++++++++++++-------
 frontend/app/lib/pages/register_page.dart | 59 ++++++++++++++++++++
 frontend/app/lib/pages/start_page.dart    | 13 +++++
 3 files changed, 120 insertions(+), 20 deletions(-)

diff --git a/frontend/app/lib/gapi/client.dart b/frontend/app/lib/gapi/client.dart
index b52a466..eb99b9b 100644
--- a/frontend/app/lib/gapi/client.dart
+++ b/frontend/app/lib/gapi/client.dart
@@ -1,10 +1,14 @@
+import 'dart:developer';
+
 import 'package:app/data/database.dart';
 import 'package:app/pb/account.pb.dart';
 import 'package:app/pb/rpc_create_account.pb.dart';
+import 'package:app/pb/rpc_get_account.pb.dart';
 import 'package:app/pb/rpc_get_account_info.pb.dart';
 import 'package:app/pb/rpc_login.pb.dart';
 import 'package:app/pb/rpc_refresh_token.pb.dart';
 import 'package:app/pb/service_df.pbgrpc.dart';
+import 'package:fixnum/fixnum.dart';
 import 'package:grpc/grpc.dart';
 
 class GClient {
@@ -18,7 +22,7 @@ class GClient {
   Map<String, String> metadata = {'Authorization': ''};
 
   late Session session;
-  late Account account;
+  Account? account;
 
   static Future<GClient> get client async {
     Session s = await Session.session;
@@ -64,11 +68,11 @@ class GClient {
       ));
       account = response.account;
       return response;
-    } on GrpcError catch (e) {
-      onError(error: e);
-      print('GRPC ERROR: ${e.message}');
-    } catch (e) {
-      print('ERROR: $e');
+    } on GrpcError catch (err) {
+      onError(error: err);
+      print('GRPC ERROR: ${err.message}');
+    } catch (err) {
+      print('ERROR: $err');
     }
     return CreateAccountResponse();
   }
@@ -96,12 +100,12 @@ class GClient {
       metadata['Authorization'] = 'Bearer ${response.accessToken}';
       onSuccess();
       return response;
-    } on GrpcError catch (e) {
-      print('caught error: ${e.message}');
+    } on GrpcError catch (err) {
+      print('caught error: ${err.message}');
       metadata['Authorization'] = '';
-      onError(error: e);
-    } catch (e) {
-      print('caught error: $e');
+      onError(error: err);
+    } catch (err) {
+      print('caught error: $err');
       metadata['Authorization'] = '';
       onError();
     }
@@ -128,12 +132,36 @@ class GClient {
       session.accessToken = response.accessToken;
       session.insertSession(session);
       return true;
-    } on GrpcError catch (e) {
-      print('caught grpc error: $e');
+    } on GrpcError catch (err) {
+      print('caught grpc error: $err');
     }
     return false;
   }
 
+  Future<GetAccountResponse> getAccount(
+      {required Int64 accountId,
+      required Function({GrpcError? err}) onError}) async {
+    GetAccountResponse response = GetAccountResponse();
+    try {
+      response = await stub.getAccount(GetAccountRequest(
+        id: accountId,
+      ));
+      account = response.account;
+    } on GrpcError catch (err) {
+      if (err.code == 16) {
+        log(err.toString());
+        onError(err: err);
+      } else {
+        log(err.toString());
+        onError();
+      }
+    } catch (err) {
+      log(err.toString());
+      onError();
+    }
+    return response;
+  }
+
   Future<GetAccountInfoResponse> getAccountInfo(GetAccountInfoRequest request,
       {required Function({String msg}) onError}) async {
     GetAccountInfoResponse response = GetAccountInfoResponse();
@@ -146,16 +174,16 @@ class GClient {
         ),
       );
       return response;
-    } on GrpcError catch (e) {
-      print('caught grpc error: ${e.message} [${e.code}]');
-      if (e.code == 16) {
+    } on GrpcError catch (err) {
+      print('caught grpc error: ${err.message} [${err.code}]');
+      if (err.code == 16) {
         onError(msg: 'Sitzung ist abgelaufen.\nBitte loggen Sie sich neu ein.');
       } else {
-        onError(msg: e.message != null ? e.message! : 'Interner Fehler');
+        onError(msg: err.message != null ? err.message! : 'Interner Fehler');
       }
-    } catch (e) {
-      print('caught error: $e');
-      onError();
+    } catch (err) {
+      print('caught error: $err');
+      onError(msg: err.toString());
     }
     return response;
   }
diff --git a/frontend/app/lib/pages/register_page.dart b/frontend/app/lib/pages/register_page.dart
index 923f72a..1257b00 100644
--- a/frontend/app/lib/pages/register_page.dart
+++ b/frontend/app/lib/pages/register_page.dart
@@ -261,6 +261,65 @@ class _RegisterPageState extends State<RegisterPage> {
                                       .then(
                                     (r) {
                                       if (r.account.secretKey != '') {
+                                        widget.client
+                                            .login(
+                                                email: mailController.text,
+                                                password:
+                                                    passwordController.text,
+                                                onError: (
+                                                    {GrpcError? error}) {},
+                                                onSuccess: () {})
+                                            .then((resp) {
+                                          widget.client.getAccount(
+                                              accountId: r.account.id,
+                                              onError: ({GrpcError? err}) {
+                                                _setLoading(false);
+                                                ScaffoldMessenger.of(context)
+                                                    .showSnackBar(
+                                                  SnackBar(
+                                                    content: const Text(
+                                                      'Login fehlgeschlagen',
+                                                    ),
+                                                    action: SnackBarAction(
+                                                        textColor: Colors.grey,
+                                                        label: 'Details',
+                                                        onPressed: () {
+                                                          showDialog(
+                                                            context: context,
+                                                            builder: (context) {
+                                                              return AlertDialog(
+                                                                content: err !=
+                                                                        null
+                                                                    ? Text(
+                                                                        'Hoppla! Da ist etwas schief gelaufen..\n\n${err.message}',
+                                                                        textAlign:
+                                                                            TextAlign.center,
+                                                                        style: const TextStyle(
+                                                                            color:
+                                                                                Colors.black),
+                                                                      )
+                                                                    : const Text(
+                                                                        'Interner Fehler',
+                                                                        textAlign:
+                                                                            TextAlign.center,
+                                                                        style: TextStyle(
+                                                                            color:
+                                                                                Colors.black),
+                                                                      ),
+                                                                icon:
+                                                                    const Icon(
+                                                                  Icons.error,
+                                                                  color: Colors
+                                                                      .black,
+                                                                ),
+                                                              );
+                                                            },
+                                                          );
+                                                        }),
+                                                  ),
+                                                );
+                                              });
+                                        });
                                         Navigator.pushAndRemoveUntil(
                                             context,
                                             MaterialPageRoute(
diff --git a/frontend/app/lib/pages/start_page.dart b/frontend/app/lib/pages/start_page.dart
index bc4578b..df44d08 100644
--- a/frontend/app/lib/pages/start_page.dart
+++ b/frontend/app/lib/pages/start_page.dart
@@ -308,6 +308,19 @@ class _StartPageState extends State<StartPage> {
                   'lib/assets/logo_300x200.png',
                 ),
               ),
+              if (widget.client.account != null &&
+                  !widget.client.account!.emailVerified)
+                Container(
+                  height: 120,
+                  width: double.infinity,
+                  padding:
+                      const EdgeInsets.symmetric(vertical: 20, horizontal: 10),
+                  child: Card(
+                    color: Colors.brown.shade300,
+                    child: const Text(
+                        'Deine E-Mail Adresse ist noch nicht validiert.'),
+                  ),
+                ),
               const SizedBox(
                 height: 40,
               ),

From 2b44a10858f9cc38fe69fa67bcc869ee07f8852c Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Wed, 1 Nov 2023 06:12:10 +0100
Subject: [PATCH 18/24] ft/adds auto refreshtoken to dashboard

---
 frontend/app/lib/pages/start_page.dart | 36 +++++++++++++-------------
 1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/frontend/app/lib/pages/start_page.dart b/frontend/app/lib/pages/start_page.dart
index df44d08..751b9dd 100644
--- a/frontend/app/lib/pages/start_page.dart
+++ b/frontend/app/lib/pages/start_page.dart
@@ -22,26 +22,16 @@ class StartPage extends StatefulWidget {
 }
 
 class _StartPageState extends State<StartPage> {
-  // List<BottomNavigationBarItem> _selectedBottomBarButtons = bottomBarButtons;
   final List<BottomNavigationBarItem> bottombarButtons = [];
 
-  // void _init() async {
-  //   final c = await GClient.client;
-  //   setState(() {
-  //     widget.client = c;
-  //   });
-  // }
-
   void _updateClient(GClient c) {
     setState(() {
-      print('GOT CLIENT: $c');
       widget.client = c;
     });
   }
 
   @override
   void initState() {
-    // _init();
     super.initState();
   }
 
@@ -170,21 +160,31 @@ class _StartPageState extends State<StartPage> {
                         children: [
                           IconButton(
                             onPressed: () async {
-                              if (!widget.client.isLoggedIn) {
+                              if (widget.client.session.accessTokenExpiresAt!
+                                  .toDateTime()
+                                  .isBefore(DateTime.now())) {
+                                await widget.client.refreshToken();
+                              }
+                              if (!widget.client.isLoggedIn &&
+                                  context.mounted) {
                                 ScaffoldMessenger.of(context).showSnackBar(
                                   const SnackBar(
                                     content: Text('Sitzung ist abgelaufen.'),
                                   ),
                                 );
-                                Navigator.pushAndRemoveUntil(
-                                    context,
-                                    MaterialPageRoute(
-                                        builder: (context) =>
-                                            LoginPage(client: widget.client)),
-                                    (route) => false);
+                                if (context.mounted) {
+                                  Navigator.pushAndRemoveUntil(
+                                      context,
+                                      MaterialPageRoute(
+                                          builder: (context) =>
+                                              LoginPage(client: widget.client)),
+                                      (route) => false);
+                                }
                               } else {
+                                final ctx = context;
+                                // ignore: use_build_context_synchronously
                                 GClient c = await Navigator.push(
-                                  context,
+                                  ctx,
                                   MaterialPageRoute(
                                     builder: (context) => DashboardPage(
                                       client: widget.client,

From 06d3b4bc19e753ddd17ef82e7e93eec1b6555044 Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Fri, 3 Nov 2023 13:43:47 +0100
Subject: [PATCH 19/24] fix/gapi.refresh_token generates invalid access_token

---
 bff/gapi/rpc_refresh_token.go | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/bff/gapi/rpc_refresh_token.go b/bff/gapi/rpc_refresh_token.go
index 10d479f..ce1d70e 100644
--- a/bff/gapi/rpc_refresh_token.go
+++ b/bff/gapi/rpc_refresh_token.go
@@ -54,14 +54,9 @@ func (server *Server) RefreshToken(ctx context.Context, req *pb.RefreshTokenRequ
 		return nil, status.Error(codes.PermissionDenied, "session expired")
 	}
 
-	id, err := server.tokenMaker.NewTokenID()
-	if err != nil {
-		slog.Error("refresh_token (token_id)", slog.Int64("invoked_by", int64(refreshPayload.AccountID)), slog.String("error", err.Error()))
-		return nil, status.Error(codes.Internal, "failed to create session token")
-	}
 	accessToken, accessPayload, err := server.tokenMaker.CreateToken(
 		refreshPayload.AccountID,
-		id,
+		session.ID,
 		server.config.AccessTokenDuration,
 	)
 	if err != nil {

From 5f0e46a1b8763c72a72b636752023ab42ac9a700 Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Fri, 3 Nov 2023 15:35:44 +0100
Subject: [PATCH 20/24] ft/adds backend service

TODO: everything new
---
 frontend/app/lib/data/database.dart           |  53 ++
 frontend/app/lib/main.dart                    |   4 +-
 frontend/app/lib/model/apis/api_response.dart |  17 +
 .../app/lib/model/apis/app_exception.dart     |  32 +
 .../lib/model/services/backend_service.dart   | 237 +++++++
 .../app/lib/model/view_model/account_vm.dart  |  56 ++
 frontend/app/lib/pages/dashboard_page.dart    | 332 +++++-----
 frontend/app/lib/pages/login_page.dart        |  85 +--
 frontend/app/lib/pages/register_page.dart     | 144 +----
 frontend/app/lib/pages/start_page.dart        | 587 +++++++++---------
 frontend/app/pubspec.lock                     |  16 +
 frontend/app/pubspec.yaml                     |   1 +
 12 files changed, 910 insertions(+), 654 deletions(-)
 create mode 100644 frontend/app/lib/model/apis/api_response.dart
 create mode 100644 frontend/app/lib/model/apis/app_exception.dart
 create mode 100644 frontend/app/lib/model/services/backend_service.dart
 create mode 100644 frontend/app/lib/model/view_model/account_vm.dart

diff --git a/frontend/app/lib/data/database.dart b/frontend/app/lib/data/database.dart
index 9cf0335..7d7e411 100644
--- a/frontend/app/lib/data/database.dart
+++ b/frontend/app/lib/data/database.dart
@@ -1,4 +1,5 @@
 import 'dart:async';
+import 'package:app/pb/session.pbjson.dart';
 import 'package:fixnum/fixnum.dart';
 
 import 'package:app/pb/google/protobuf/timestamp.pb.dart';
@@ -40,6 +41,12 @@ class Session {
     );
     Session s = Session();
     s._database = db;
+    final sessions = await s.getSessions();
+    if (sessions.isNotEmpty) {
+      final session = sessions[0];
+      session._database = db;
+      return session;
+    }
     return s;
   }
 
@@ -90,6 +97,41 @@ class Session {
     return 'Session{accountId: $accountId, sessionId: $sessionId, accessToken: $accessToken, accessTokenExpiresAt: ${accessTokenExpiresAt.toString()}, refreshToken: $refreshToken, refreshTokenExpiresAt: ${refreshTokenExpiresAt.toString()}}';
   }
 
+  static newSession(Session session) async {
+    final db = await openDatabase(
+      join(await getDatabasesPath(), 'df_database.db'),
+      onCreate: (db, version) {
+        return db.execute(
+          'CREATE TABLE sessions(accountId INTEGER PRIMARY KEY, sessionId TEXT, accessToken TEXT, accessTokenExpiresAt TEXT, refreshToken TEXT, refreshTokenExpiresAt TEXT)',
+        );
+      },
+      version: 1,
+    );
+
+    await db.insert(
+      'sessions',
+      session.toMap(),
+      conflictAlgorithm: ConflictAlgorithm.replace,
+    );
+  }
+
+  static Future<Session> updateToken(Session s) async {
+    final db = await openDatabase(
+      join(await getDatabasesPath(), 'df_database.db'),
+      onCreate: (db, version) {
+        return db.execute(
+          'CREATE TABLE sessions(accountId INTEGER PRIMARY KEY, sessionId TEXT, accessToken TEXT, accessTokenExpiresAt TEXT, refreshToken TEXT, refreshTokenExpiresAt TEXT)',
+        );
+      },
+      version: 1,
+    );
+    await db.update(
+      'sessions',
+      s.toMap(),
+    );
+    return s; //await getSession(s.accountId!);
+  }
+
   Future<void> insertSession(Session session) async {
     // print('INSERTING SESSION: ${session.sessionId}');
     final db = _database;
@@ -101,6 +143,17 @@ class Session {
     // print('INSERT RESULT: $result');
   }
 
+  Future<Session> updateSession(Session session) async {
+    sessionId = session.sessionId;
+    accessToken = session.accessToken;
+    accessTokenExpiresAt = session.accessTokenExpiresAt;
+    refreshToken = session.refreshToken;
+    refreshTokenExpiresAt = session.refreshTokenExpiresAt;
+    final db = _database;
+    await db.update('sessions', session.toMap());
+    return session;
+  }
+
   Future<void> removeSession(String sessionId) async {
     final db = _database;
     await db.delete('sessions', where: 'sessionId = ?', whereArgs: [sessionId]);
diff --git a/frontend/app/lib/main.dart b/frontend/app/lib/main.dart
index 8e44a71..e790121 100644
--- a/frontend/app/lib/main.dart
+++ b/frontend/app/lib/main.dart
@@ -45,8 +45,8 @@ void main() async {
           )),
       home: Background(
         child: StartPage(
-          client: await GClient.client,
-        ),
+            // client: await GClient.client,
+            ),
       ),
     ),
   );
diff --git a/frontend/app/lib/model/apis/api_response.dart b/frontend/app/lib/model/apis/api_response.dart
new file mode 100644
index 0000000..764c500
--- /dev/null
+++ b/frontend/app/lib/model/apis/api_response.dart
@@ -0,0 +1,17 @@
+class ApiResponse<T> {
+  Status status;
+  T? data;
+  String? message;
+
+  ApiResponse.initial(this.message) : status = Status.INITIAL;
+  ApiResponse.loading(this.message) : status = Status.LOADING;
+  ApiResponse.completed(this.data, this.message) : status = Status.COMPLETED;
+  ApiResponse.error(this.message) : status = Status.ERROR;
+
+  @override
+  String toString() {
+    return "Status : $status \n Message: $message \n Data : $data";
+  }
+}
+
+enum Status { INITIAL, LOADING, COMPLETED, ERROR }
diff --git a/frontend/app/lib/model/apis/app_exception.dart b/frontend/app/lib/model/apis/app_exception.dart
new file mode 100644
index 0000000..7093126
--- /dev/null
+++ b/frontend/app/lib/model/apis/app_exception.dart
@@ -0,0 +1,32 @@
+class AppException implements Exception {
+  final _message;
+  final _prefix;
+
+  AppException([this._message, this._prefix]);
+
+  String toString() {
+    return "$_prefix$_message";
+  }
+}
+
+class FetchDataException extends AppException {
+  FetchDataException([String? message])
+      : super(message, 'Fehler bei der Kommunikation: ');
+}
+
+class BadRequestException extends AppException {
+  BadRequestException([message]) : super(message, 'Ungültige Anfrage; ');
+}
+
+class UnauthorizedException extends AppException {
+  UnauthorizedException([message])
+      : super(message, 'Nicht authorisierte Anfrage; ');
+}
+
+class InvalidInputException extends AppException {
+  InvalidInputException([message]) : super(message, 'Ungültige Eingabe; ');
+}
+
+class InternalException extends AppException {
+  InternalException([message]) : super(message, 'Interner Fehler; ');
+}
diff --git a/frontend/app/lib/model/services/backend_service.dart b/frontend/app/lib/model/services/backend_service.dart
new file mode 100644
index 0000000..6cc42d0
--- /dev/null
+++ b/frontend/app/lib/model/services/backend_service.dart
@@ -0,0 +1,237 @@
+import 'dart:io';
+
+import 'package:app/model/apis/app_exception.dart';
+import 'package:app/pb/account.pb.dart';
+import 'package:app/pb/account_info.pb.dart';
+import 'package:app/pb/person.pb.dart';
+import 'package:app/data/database.dart';
+import 'package:app/pb/rpc_get_account.pb.dart';
+import 'package:app/pb/rpc_get_account_info.pb.dart';
+import 'package:app/pb/rpc_get_person.pb.dart';
+import 'package:app/pb/rpc_login.pb.dart';
+import 'package:app/pb/rpc_refresh_token.pb.dart';
+import 'package:app/pb/service_df.pbgrpc.dart';
+import 'package:fixnum/fixnum.dart';
+import 'package:grpc/grpc.dart';
+import 'package:sqflite/sqflite.dart';
+
+class BackendService {
+  BackendService() {
+    _init();
+  }
+  final String baseUrl = '10.0.0.2';
+  final String port = '9090';
+
+  late Session _session;
+
+  final dfClient _client = dfClient(
+    ClientChannel('10.0.2.2',
+        port: 9090,
+        options: const ChannelOptions(
+          credentials: ChannelCredentials.insecure(),
+        )),
+    options: CallOptions(
+      timeout: const Duration(seconds: 5),
+    ),
+  );
+
+  static get client => dfClient(
+        ClientChannel('10.0.2.2',
+            port: 9090,
+            options: const ChannelOptions(
+              credentials: ChannelCredentials.insecure(),
+            )),
+        options: CallOptions(
+          timeout: const Duration(seconds: 5),
+        ),
+      );
+
+  void _init() {
+    Session.session.then((value) => _session = value);
+  }
+
+  Future<Session?> _isLoggedIn() async {
+    Session session = await Session.session;
+    if (session.accessToken == null ||
+        session.refreshToken == null ||
+        session.accountId == null) {
+      return null;
+    }
+
+    if (session.accessTokenExpiresAt == null) {
+      return null;
+    }
+
+    if (session.refreshTokenExpiresAt == null) {
+      return null;
+    }
+
+    if (session.refreshTokenExpiresAt!.toDateTime().isBefore(DateTime.now())) {
+      return null;
+    } else {
+      if (session.refreshToken != null &&
+          session.accessTokenExpiresAt!.toDateTime().isBefore(DateTime.now())) {
+        session = await refreshToken(session);
+      }
+    }
+
+    return session;
+  }
+
+  static Future<bool> get isLoggedIn async {
+    Session session = await Session.session;
+    if (session.accessToken == null ||
+        session.refreshToken == null ||
+        session.accountId == null) {
+      return false;
+    }
+
+    if (session.accessTokenExpiresAt == null) {
+      return false;
+    }
+
+    if (session.refreshTokenExpiresAt == null) {
+      return false;
+    }
+
+    if (session.refreshTokenExpiresAt!.toDateTime().isBefore(DateTime.now())) {
+      return false;
+    }
+
+    return true;
+  }
+
+  Future<Account> getAccount() async {
+    Session? session = await _isLoggedIn();
+    if (session == null) {
+      throw UnauthorizedException('Sitzung ist abgelaufen');
+    }
+    try {
+      final GetAccountResponse response = await _client.getAccount(
+          GetAccountRequest(id: session!.accountId),
+          options: CallOptions(
+              metadata: {'Authorization': 'Bearer ${session.accessToken}'}));
+      return response.account;
+    } on SocketException {
+      throw FetchDataException('Keine Internet Verbindung');
+    } on GrpcError catch (err) {
+      // if (err.code == 16) {
+      //   await refreshToken(session);
+      //   return getAccount();
+      // }
+      throw FetchDataException(err.message);
+    } catch (err) {
+      throw InternalException(err.toString());
+    }
+  }
+
+  Future<AccountInfo> getAccountInfo() async {
+    Session session = await Session.session;
+    if (session.accessTokenExpiresAt == null) {
+      throw UnauthorizedException('Keine Siztung gefunden');
+    }
+    if (session.accessTokenExpiresAt!.toDateTime().isBefore(DateTime.now())) {
+      session = await refreshToken(session);
+      if (session.accessTokenExpiresAt!.toDateTime().isBefore(DateTime.now())) {
+        throw UnauthorizedException('Sitzung ist abgelaufen');
+      }
+    }
+    try {
+      final GetAccountInfoResponse response = await _client
+          .getAccountInfo(GetAccountInfoRequest(accountId: _session.accountId));
+      return response.accountInfo;
+    } on SocketException {
+      throw FetchDataException('Keine Internet Verbindung');
+    } on GrpcError catch (err) {
+      if (err.code == 16) {
+        await refreshToken(session);
+        return getAccountInfo();
+      }
+      throw FetchDataException(err.message);
+    } catch (err) {
+      throw InternalException(err.toString());
+    }
+  }
+
+  Future<Person> getPerson(Int64 personId) async {
+    Session session = await Session.session;
+    if (session.accessTokenExpiresAt == null) {
+      throw UnauthorizedException('Keine Siztung gefunden');
+    }
+    if (session.accessTokenExpiresAt!.toDateTime().isBefore(DateTime.now())) {
+      session = await refreshToken(session);
+      if (session.accessTokenExpiresAt == null) {
+        throw UnauthorizedException('Sitzung ist abgelaufen');
+      }
+    }
+    try {
+      final GetPersonResponse response =
+          await _client.getPerson(GetPersonRequest(id: personId));
+      return response.person;
+    } on SocketException {
+      throw FetchDataException('Keine Internet Verbindung');
+    } on GrpcError catch (err) {
+      throw FetchDataException(err.message);
+    } catch (err) {
+      throw InternalException(err.toString());
+    }
+  }
+
+  // Future<List<Person>> listPersons() async {
+  //   if (_session.accessToken == null) {
+  //     refreshToken();
+  //   }
+  //   try {
+  //     ListPersonsResponse response =
+  //         await _client.listPersons(ListPersonsRequest(accountId: _session.accountId));
+  //     return response.persons;
+  //   } on SocketException {
+  //     throw FetchDataException('Keine Internet Verbindung');
+  //   } on GrpcError catch (err) {
+  //     throw FetchDataException(err.message);
+  //   } catch (err) {
+  //     throw InternalException(err.toString());
+  //   }
+  // }
+  static Future<bool> login(
+      {required String email, required String password}) async {
+    try {
+      final LoginResponse response = await BackendService.client.login(
+        LoginRequest(
+          email: email,
+          password: password,
+        ),
+      );
+      await Session.newSession(response as Session);
+      return response.accessToken != '';
+    } on SocketException {
+      throw FetchDataException('Keine Internet Verbindung');
+    } on GrpcError catch (err) {
+      throw FetchDataException(err.message);
+    } catch (err) {
+      throw InternalException(err.toString());
+    }
+  }
+
+  Future<Session> refreshToken(Session session) async {
+    try {
+      final RefreshTokenResponse response = await _client.refreshToken(
+          RefreshTokenRequest(refreshToken: session.refreshToken));
+      session.accessToken = response.accessToken;
+      session.accessTokenExpiresAt = response.accessTokenExpiresAt;
+      session = await Session.updateToken(session);
+      return session;
+    } on SocketException {
+      throw FetchDataException('Keine Internet Verbindung');
+    } on GrpcError catch (err) {
+      throw FetchDataException(err.message);
+    } catch (err) {
+      throw InternalException(err.toString());
+    }
+  }
+
+  static Future<void> logout() async {
+    Session session = await Session.session;
+    session.reset();
+  }
+}
diff --git a/frontend/app/lib/model/view_model/account_vm.dart b/frontend/app/lib/model/view_model/account_vm.dart
new file mode 100644
index 0000000..13356fa
--- /dev/null
+++ b/frontend/app/lib/model/view_model/account_vm.dart
@@ -0,0 +1,56 @@
+import 'package:app/model/apis/api_response.dart';
+import 'package:app/model/services/backend_service.dart';
+import 'package:app/pb/account.pb.dart';
+import 'package:flutter/material.dart';
+
+class AccountViewModel with ChangeNotifier {
+  AccountViewModel() {
+    _init();
+  }
+  ApiResponse _apiResponse = ApiResponse.initial('Keine Daten');
+
+  final BackendService _service = BackendService();
+  Account? _account;
+
+  ApiResponse get response {
+    return _apiResponse;
+  }
+
+  Account? get account {
+    return _account;
+  }
+
+  void _init() async {
+    _apiResponse = ApiResponse.loading('Bereite alles vor');
+    try {
+      _apiResponse = ApiResponse.completed(await _service.getAccount(), 'done');
+    } catch (e) {
+      _apiResponse = ApiResponse.error(e.toString());
+    }
+    notifyListeners();
+  }
+
+  Future<void> fetchAccount() async {
+    _apiResponse = ApiResponse.loading('Hole Account');
+    notifyListeners();
+    try {
+      _apiResponse = ApiResponse.completed(await _service.getAccount(), 'done');
+    } catch (e) {
+      _apiResponse = ApiResponse.error(e.toString());
+    }
+    notifyListeners();
+  }
+
+  Future<void> logout() async {
+    _apiResponse = ApiResponse.loading('Logge aus');
+    notifyListeners();
+    try {
+      await BackendService.logout();
+      _apiResponse = ApiResponse.completed(null, 'Erfolgreich ausgeloggt');
+    } catch (e) {
+      _apiResponse = ApiResponse.error(e.toString());
+    }
+    print(_apiResponse.message);
+    notifyListeners();
+  }
+}
diff --git a/frontend/app/lib/pages/dashboard_page.dart b/frontend/app/lib/pages/dashboard_page.dart
index 6be86ba..14d3a25 100644
--- a/frontend/app/lib/pages/dashboard_page.dart
+++ b/frontend/app/lib/pages/dashboard_page.dart
@@ -11,10 +11,10 @@ import 'package:flutter/material.dart';
 class DashboardPage extends StatefulWidget {
   const DashboardPage({
     super.key,
-    required this.client,
+    // required this.client,
   });
 
-  final GClient client;
+  // final GClient client;
 
   @override
   State<DashboardPage> createState() => _DashboardPageState();
@@ -35,44 +35,44 @@ class _DashboardPageState extends State<DashboardPage> {
     super.initState();
 
     _setLoading(true);
-    widget.client.getAccountInfo(
-      GetAccountInfoRequest(
-        accountId: widget.client.session.accountId,
-      ),
-      onError: ({String? msg}) {
-        ScaffoldMessenger.of(context).showSnackBar(
-          SnackBar(
-            content: const Text('AccountInfo konnte nicht geladen werden'),
-            action: msg != null
-                ? SnackBarAction(
-                    label: 'Details',
-                    textColor: Colors.grey,
-                    onPressed: () {
-                      showDialog(
-                        context: context,
-                        builder: (context) {
-                          return AlertDialog(
-                            content: Text(
-                              msg,
-                              textAlign: TextAlign.center,
-                              style: const TextStyle(color: Colors.black),
-                            ),
-                            icon: const Icon(
-                              Icons.warning,
-                              color: Colors.red,
-                            ),
-                          );
-                        },
-                      );
-                    })
-                : null,
-          ),
-        );
-      },
-    ).then((value) {
-      accountInfo = value.accountInfo;
-      _setLoading(false);
-    });
+    // widget.client.getAccountInfo(
+    //   GetAccountInfoRequest(
+    //     accountId: widget.client.session.accountId,
+    //   ),
+    //   onError: ({String? msg}) {
+    //     ScaffoldMessenger.of(context).showSnackBar(
+    //       SnackBar(
+    //         content: const Text('AccountInfo konnte nicht geladen werden'),
+    //         action: msg != null
+    //             ? SnackBarAction(
+    //                 label: 'Details',
+    //                 textColor: Colors.grey,
+    //                 onPressed: () {
+    //                   showDialog(
+    //                     context: context,
+    //                     builder: (context) {
+    //                       return AlertDialog(
+    //                         content: Text(
+    //                           msg,
+    //                           textAlign: TextAlign.center,
+    //                           style: const TextStyle(color: Colors.black),
+    //                         ),
+    //                         icon: const Icon(
+    //                           Icons.warning,
+    //                           color: Colors.red,
+    //                         ),
+    //                       );
+    //                     },
+    //                   );
+    //                 })
+    //             : null,
+    //       ),
+    //     );
+    //   },
+    // ).then((value) {
+    //   accountInfo = value.accountInfo;
+    //   _setLoading(false);
+    // });
   }
 
   @override
@@ -144,139 +144,139 @@ class _DashboardPageState extends State<DashboardPage> {
                   ],
                 ),
               ),
-              if (widget.client.session.accessToken != null)
-                TextButton(
-                  onPressed: () {
-                    widget.client.session.accessToken = null;
-                    widget.client.session
-                        .removeSession(widget.client.session.sessionId!);
+              // if (widget.client.session.accessToken != null)
+              //   TextButton(
+              //     onPressed: () {
+              //       widget.client.session.accessToken = null;
+              //       widget.client.session
+              //           .removeSession(widget.client.session.sessionId!);
 
-                    Navigator.of(context).pushAndRemoveUntil(
-                        MaterialPageRoute(
-                          builder: (context) =>
-                              StartPage(client: widget.client),
-                        ),
-                        (route) => false);
-                  },
-                  child: const Row(
-                    children: [
-                      Text(
-                        'Log out',
-                        style: TextStyle(fontSize: 20),
-                      ),
-                      Spacer(),
-                      Icon(
-                        Icons.logout,
-                        color: Colors.white,
-                      ),
-                    ],
-                  ),
-                ),
+              //       Navigator.of(context).pushAndRemoveUntil(
+              //           MaterialPageRoute(
+              //             builder: (context) =>
+              //                 StartPage(client: widget.client),
+              //           ),
+              //           (route) => false);
+              //     },
+              //     child: const Row(
+              //       children: [
+              //         Text(
+              //           'Log out',
+              //           style: TextStyle(fontSize: 20),
+              //         ),
+              //         Spacer(),
+              //         Icon(
+              //           Icons.logout,
+              //           color: Colors.white,
+              //         ),
+              //       ],
+              //     ),
+              //   ),
               const SizedBox(
                 height: 250,
               )
             ],
           );
         }),
-        bottomNavigationBar: Builder(
-          builder: (context) {
-            return BottomBar(
-              children: widget.client.session.accessToken != null
-                  ? [
-                      BottomNavigationBarItem(
-                        backgroundColor: Colors.white,
-                        label: 'Personen',
-                        icon: Column(
-                          children: [
-                            IconButton(
-                              onPressed: () =>
-                                  Scaffold.of(context).openDrawer(),
-                              icon: const Icon(
-                                Icons.group,
-                                color: Colors.white,
-                              ),
-                            ),
-                            const Text(
-                              'Personen',
-                              style: TextStyle(
-                                color: Colors.white,
-                                fontSize: 16,
-                              ),
-                            )
-                          ],
-                        ),
-                      ),
-                      BottomNavigationBarItem(
-                        backgroundColor: Colors.white,
-                        label: 'Home',
-                        icon: Column(
-                          children: [
-                            IconButton(
-                              onPressed: () {
-                                Navigator.of(context).push(
-                                  MaterialPageRoute(
-                                    builder: (context) => StartPage(
-                                      client: widget.client,
-                                    ),
-                                  ),
-                                );
-                              },
-                              icon: const Icon(
-                                Icons.home,
-                                color: Colors.white,
-                              ),
-                            ),
-                            const Text(
-                              'Home',
-                              style: TextStyle(
-                                color: Colors.white,
-                                fontSize: 16,
-                              ),
-                            )
-                          ],
-                        ),
-                      ),
-                      BottomNavigationBarItem(
-                        backgroundColor: Colors.white,
-                        label: 'Menu',
-                        icon: IconButton(
-                          onPressed: () {
-                            Scaffold.of(context).openDrawer();
-                          },
-                          icon: const Icon(
-                            Icons.menu,
-                            color: Colors.white,
-                          ),
-                        ),
-                      )
-                    ]
-                  : [
-                      BottomNavigationBarItem(
-                        label: 'back',
-                        backgroundColor: Colors.white,
-                        icon: IconButton(
-                          onPressed: () {},
-                          icon: const Icon(
-                            Icons.arrow_back,
-                            color: Colors.white,
-                          ),
-                        ),
-                      ),
-                      BottomNavigationBarItem(
-                        backgroundColor: Colors.white,
-                        label: 'Menu',
-                        icon: IconButton(
-                          onPressed: () => Scaffold.of(context).openDrawer(),
-                          icon: const Icon(
-                            Icons.menu,
-                            color: Colors.white,
-                          ),
-                        ),
-                      ),
-                    ],
-            );
-          },
-        ),
+        // bottomNavigationBar: Builder(
+        //   builder: (context) {
+        //     return BottomBar(
+        //       children: widget.client.session.accessToken != null
+        //           ? [
+        //               BottomNavigationBarItem(
+        //                 backgroundColor: Colors.white,
+        //                 label: 'Personen',
+        //                 icon: Column(
+        //                   children: [
+        //                     IconButton(
+        //                       onPressed: () =>
+        //                           Scaffold.of(context).openDrawer(),
+        //                       icon: const Icon(
+        //                         Icons.group,
+        //                         color: Colors.white,
+        //                       ),
+        //                     ),
+        //                     const Text(
+        //                       'Personen',
+        //                       style: TextStyle(
+        //                         color: Colors.white,
+        //                         fontSize: 16,
+        //                       ),
+        //                     )
+        //                   ],
+        //                 ),
+        //               ),
+        //               BottomNavigationBarItem(
+        //                 backgroundColor: Colors.white,
+        //                 label: 'Home',
+        //                 icon: Column(
+        //                   children: [
+        //                     IconButton(
+        //                       onPressed: () {
+        //                         Navigator.of(context).push(
+        //                           MaterialPageRoute(
+        //                             builder: (context) => StartPage(
+        //                               client: widget.client,
+        //                             ),
+        //                           ),
+        //                         );
+        //                       },
+        //                       icon: const Icon(
+        //                         Icons.home,
+        //                         color: Colors.white,
+        //                       ),
+        //                     ),
+        //                     const Text(
+        //                       'Home',
+        //                       style: TextStyle(
+        //                         color: Colors.white,
+        //                         fontSize: 16,
+        //                       ),
+        //                     )
+        //                   ],
+        //                 ),
+        //               ),
+        //               BottomNavigationBarItem(
+        //                 backgroundColor: Colors.white,
+        //                 label: 'Menu',
+        //                 icon: IconButton(
+        //                   onPressed: () {
+        //                     Scaffold.of(context).openDrawer();
+        //                   },
+        //                   icon: const Icon(
+        //                     Icons.menu,
+        //                     color: Colors.white,
+        //                   ),
+        //                 ),
+        //               )
+        //             ]
+        //           : [
+        //               BottomNavigationBarItem(
+        //                 label: 'back',
+        //                 backgroundColor: Colors.white,
+        //                 icon: IconButton(
+        //                   onPressed: () {},
+        //                   icon: const Icon(
+        //                     Icons.arrow_back,
+        //                     color: Colors.white,
+        //                   ),
+        //                 ),
+        //               ),
+        //               BottomNavigationBarItem(
+        //                 backgroundColor: Colors.white,
+        //                 label: 'Menu',
+        //                 icon: IconButton(
+        //                   onPressed: () => Scaffold.of(context).openDrawer(),
+        //                   icon: const Icon(
+        //                     Icons.menu,
+        //                     color: Colors.white,
+        //                   ),
+        //                 ),
+        //               ),
+        //             ],
+        //     );
+        //   },
+        // ),
         body: !_loading
             ? Background(
                 child: Center(
diff --git a/frontend/app/lib/pages/login_page.dart b/frontend/app/lib/pages/login_page.dart
index daf5e9b..b7d49d2 100644
--- a/frontend/app/lib/pages/login_page.dart
+++ b/frontend/app/lib/pages/login_page.dart
@@ -1,4 +1,5 @@
 import 'package:app/gapi/client.dart';
+import 'package:app/model/services/backend_service.dart';
 import 'package:app/pages/start_page.dart';
 import 'package:app/widgets/background.dart';
 import 'package:app/widgets/bottom_bar.dart';
@@ -12,11 +13,11 @@ import 'package:grpc/grpc.dart';
 class LoginPage extends StatefulWidget {
   const LoginPage({
     super.key,
-    required this.client,
+    // required this.client,
     // required this.onChangePage,
   });
 
-  final GClient client;
+  // final GClient client;
   // void Function(Pages page) onChangePage;
 
   @override
@@ -87,7 +88,7 @@ class _LoginPageState extends State<LoginPage> {
               label: 'back',
               backgroundColor: Colors.white,
               icon: IconButton(
-                onPressed: () => Navigator.of(context).pop(widget.client),
+                onPressed: () => Navigator.of(context).pop(),
                 icon: const Icon(
                   Icons.arrow_back,
                   color: Colors.white,
@@ -250,73 +251,23 @@ class _LoginPageState extends State<LoginPage> {
                               if (_formKey.currentState!.validate()) {
                                 // final navigator = Navigator.of(context);
                                 _setLoading(true);
-                                widget.client
-                                    .login(
+                                BackendService.login(
                                   email: mailController.text,
                                   password: passwordController.text,
-                                  onError: ({GrpcError? error}) {
-                                    _setLoading(false);
-                                    ScaffoldMessenger.of(context)
-                                        .showSnackBar(SnackBar(
-                                      content: const Text(
-                                        'Login fehlgeschlagen',
-                                      ),
-                                      action: SnackBarAction(
-                                          textColor: Colors.grey,
-                                          label: 'Details',
-                                          onPressed: () {
-                                            showDialog(
-                                              context: context,
-                                              builder: (context) {
-                                                return AlertDialog(
-                                                  content: error != null
-                                                      ? Text(
-                                                          'Fehler: ${error.message}',
-                                                          textAlign:
-                                                              TextAlign.center,
-                                                          style:
-                                                              const TextStyle(
-                                                                  color: Colors
-                                                                      .black),
-                                                        )
-                                                      : const Text(
-                                                          'Interner Fehler',
-                                                          textAlign:
-                                                              TextAlign.center,
-                                                          style: TextStyle(
-                                                              color:
-                                                                  Colors.black),
-                                                        ),
-                                                  icon: const Icon(
-                                                    Icons.error,
-                                                    color: Colors.black,
-                                                  ),
-                                                );
-                                              },
-                                            );
-                                          }),
-                                    ));
-                                  },
-                                  onSuccess: () {
-                                    // _setLoading(false);
-                                    ScaffoldMessenger.of(context)
-                                        .showSnackBar(const SnackBar(
-                                      content: Text('Login erfolgreich'),
-                                    ));
-                                  },
-                                )
-                                    .then(
+                                ).then(
                                   (r) {
-                                    if (r.accessToken != '') {
-                                      Navigator.pushAndRemoveUntil(
-                                        context,
-                                        MaterialPageRoute(
-                                          builder: (ctx) => StartPage(
-                                            client: widget.client,
-                                          ),
-                                        ),
-                                        (ctx) => false,
-                                      );
+                                    if (r) {
+                                      Navigator.pop(context);
+                                      Navigator.pop(context);
+                                      // Navigator.pushAndRemoveUntil(
+                                      //   context,
+                                      //   MaterialPageRoute(
+                                      //     builder: (ctx) => const StartPage(
+                                      //         // client: widget.client,
+                                      //         ),
+                                      //   ),
+                                      //   (ctx) => false,
+                                      // );
                                       // widget.onChangePage(
                                       //   Pages.dashboard,
                                       // );
diff --git a/frontend/app/lib/pages/register_page.dart b/frontend/app/lib/pages/register_page.dart
index 1257b00..d5ee106 100644
--- a/frontend/app/lib/pages/register_page.dart
+++ b/frontend/app/lib/pages/register_page.dart
@@ -10,10 +10,10 @@ import 'package:grpc/grpc.dart';
 class RegisterPage extends StatefulWidget {
   const RegisterPage({
     super.key,
-    required this.client,
+    // required this.client,
   });
 
-  final GClient client;
+  // final GClient client;
 
   @override
   State<RegisterPage> createState() => _RegisterPageState();
@@ -112,7 +112,7 @@ class _RegisterPageState extends State<RegisterPage> {
                 label: 'back',
                 backgroundColor: Colors.white,
                 icon: IconButton(
-                  onPressed: () => Navigator.of(context).pop(widget.client),
+                  onPressed: () => Navigator.of(context).pop(),
                   icon: const Icon(
                     Icons.arrow_back,
                     color: Colors.white,
@@ -209,143 +209,7 @@ class _RegisterPageState extends State<RegisterPage> {
                           ElevatedButton(
                               onPressed: () {
                                 if (_formKey.currentState!.validate()) {
-                                  _setLoading(true);
-                                  widget.client
-                                      .createAccount(
-                                          email: mailController.text,
-                                          password: passwordController.text,
-                                          onError: ({GrpcError? error}) {
-                                            _setLoading(false);
-                                            ScaffoldMessenger.of(context)
-                                                .showSnackBar(SnackBar(
-                                              content: const Text(
-                                                'Login fehlgeschlagen',
-                                              ),
-                                              action: SnackBarAction(
-                                                  textColor: Colors.grey,
-                                                  label: 'Details',
-                                                  onPressed: () {
-                                                    showDialog(
-                                                      context: context,
-                                                      builder: (context) {
-                                                        return AlertDialog(
-                                                          content: error != null
-                                                              ? Text(
-                                                                  'Fehler: ${error.message}',
-                                                                  textAlign:
-                                                                      TextAlign
-                                                                          .center,
-                                                                  style: const TextStyle(
-                                                                      color: Colors
-                                                                          .black),
-                                                                )
-                                                              : const Text(
-                                                                  'Interner Fehler',
-                                                                  textAlign:
-                                                                      TextAlign
-                                                                          .center,
-                                                                  style: TextStyle(
-                                                                      color: Colors
-                                                                          .black),
-                                                                ),
-                                                          icon: const Icon(
-                                                            Icons.error,
-                                                            color: Colors.black,
-                                                          ),
-                                                        );
-                                                      },
-                                                    );
-                                                  }),
-                                            ));
-                                          })
-                                      .then(
-                                    (r) {
-                                      if (r.account.secretKey != '') {
-                                        widget.client
-                                            .login(
-                                                email: mailController.text,
-                                                password:
-                                                    passwordController.text,
-                                                onError: (
-                                                    {GrpcError? error}) {},
-                                                onSuccess: () {})
-                                            .then((resp) {
-                                          widget.client.getAccount(
-                                              accountId: r.account.id,
-                                              onError: ({GrpcError? err}) {
-                                                _setLoading(false);
-                                                ScaffoldMessenger.of(context)
-                                                    .showSnackBar(
-                                                  SnackBar(
-                                                    content: const Text(
-                                                      'Login fehlgeschlagen',
-                                                    ),
-                                                    action: SnackBarAction(
-                                                        textColor: Colors.grey,
-                                                        label: 'Details',
-                                                        onPressed: () {
-                                                          showDialog(
-                                                            context: context,
-                                                            builder: (context) {
-                                                              return AlertDialog(
-                                                                content: err !=
-                                                                        null
-                                                                    ? Text(
-                                                                        'Hoppla! Da ist etwas schief gelaufen..\n\n${err.message}',
-                                                                        textAlign:
-                                                                            TextAlign.center,
-                                                                        style: const TextStyle(
-                                                                            color:
-                                                                                Colors.black),
-                                                                      )
-                                                                    : const Text(
-                                                                        'Interner Fehler',
-                                                                        textAlign:
-                                                                            TextAlign.center,
-                                                                        style: TextStyle(
-                                                                            color:
-                                                                                Colors.black),
-                                                                      ),
-                                                                icon:
-                                                                    const Icon(
-                                                                  Icons.error,
-                                                                  color: Colors
-                                                                      .black,
-                                                                ),
-                                                              );
-                                                            },
-                                                          );
-                                                        }),
-                                                  ),
-                                                );
-                                              });
-                                        });
-                                        Navigator.pushAndRemoveUntil(
-                                            context,
-                                            MaterialPageRoute(
-                                                builder: (builder) => StartPage(
-                                                    client: widget.client)),
-                                            (route) => false);
-                                        showDialog(
-                                            context: context,
-                                            builder: (builder) {
-                                              return const AlertDialog(
-                                                content: Text(
-                                                  'Account wurde angelegt',
-                                                  textAlign: TextAlign.center,
-                                                  style: TextStyle(
-                                                      color: Colors.black),
-                                                ),
-                                                icon: Icon(
-                                                  Icons.done,
-                                                  size: 50,
-                                                ),
-                                                iconColor: Colors.green,
-                                              );
-                                            });
-                                      }
-                                    },
-                                  );
+                                  // _setLoading(true);
                                 }
                               },
                               child: const Icon(Icons.login))
diff --git a/frontend/app/lib/pages/start_page.dart b/frontend/app/lib/pages/start_page.dart
index 751b9dd..39d6ecf 100644
--- a/frontend/app/lib/pages/start_page.dart
+++ b/frontend/app/lib/pages/start_page.dart
@@ -1,21 +1,26 @@
 import 'package:app/gapi/client.dart';
+import 'package:app/model/apis/api_response.dart';
+import 'package:app/model/view_model/account_vm.dart';
 import 'package:app/pages/dashboard_page.dart';
 import 'package:app/pages/login_page.dart';
 import 'package:app/pages/register_page.dart';
+import 'package:app/pb/account.pb.dart';
 import 'package:app/widgets/background.dart';
 import 'package:app/widgets/bottom_bar.dart';
 import 'package:app/widgets/side_drawer.dart';
 import 'package:flutter/material.dart';
 import 'dart:core';
 
+import 'package:provider/provider.dart';
+
 // ignore: must_be_immutable
 class StartPage extends StatefulWidget {
-  StartPage({
+  const StartPage({
     super.key,
-    required this.client,
+    // required this.client,
   });
 
-  GClient client;
+  // GClient client;
 
   @override
   State<StartPage> createState() => _StartPageState();
@@ -24,320 +29,344 @@ class StartPage extends StatefulWidget {
 class _StartPageState extends State<StartPage> {
   final List<BottomNavigationBarItem> bottombarButtons = [];
 
-  void _updateClient(GClient c) {
-    setState(() {
-      widget.client = c;
-    });
-  }
+  // void _updateClient(GClient c) {
+  //   setState(() {
+  //     widget.client = c;
+  //   });
+  // }
 
   @override
   void initState() {
     super.initState();
   }
 
+  SnackBar _snackBar(BuildContext context, String message, String label,
+      void Function() action) {
+    ScaffoldMessenger.of(context).removeCurrentSnackBar();
+    // ScaffoldMessenger.of(context).clearSnackBars();
+    return SnackBar(
+      content: Text(
+        message,
+        style: const TextStyle(color: Colors.black),
+      ),
+      backgroundColor: Colors.white,
+      action: SnackBarAction(
+        label: label,
+        onPressed: action,
+      ),
+    );
+  }
+
   @override
   Widget build(BuildContext context) {
     return Background(
-      child: Scaffold(
-        appBar: AppBar(
-          automaticallyImplyLeading: false,
-        ),
-        drawer: Builder(builder: (context) {
-          return SideDrawer(children: [
-            const Spacer(),
-            TextButton(
-              onPressed: () {
-                Scaffold.of(context).closeDrawer();
-              },
-              child: const Row(
-                children: [
-                  Text(
-                    'About',
-                    style: TextStyle(fontSize: 20),
-                  ),
-                  Spacer(),
-                  Icon(
-                    Icons.question_answer,
-                    color: Colors.white,
-                  ),
-                ],
-              ),
+      child: ChangeNotifierProvider<AccountViewModel>(
+        create: (context) => AccountViewModel(),
+        child: Consumer<AccountViewModel>(builder: (context, value, child) {
+          return Scaffold(
+            appBar: AppBar(
+              automaticallyImplyLeading: false,
             ),
-            TextButton(
-              onPressed: () {
-                Scaffold.of(context).closeDrawer();
-              },
-              child: const Row(
-                children: [
-                  Text(
-                    'Datenschutz',
-                    style: TextStyle(fontSize: 20),
+            drawer: Builder(builder: (context) {
+              return SideDrawer(children: [
+                const Spacer(),
+                TextButton(
+                  onPressed: () {
+                    Scaffold.of(context).closeDrawer();
+                  },
+                  child: const Row(
+                    children: [
+                      Text(
+                        'About',
+                        style: TextStyle(fontSize: 20),
+                      ),
+                      Spacer(),
+                      Icon(
+                        Icons.question_answer,
+                        color: Colors.white,
+                      ),
+                    ],
                   ),
-                  Spacer(),
-                  Icon(
-                    Icons.privacy_tip,
-                    color: Colors.white,
+                ),
+                TextButton(
+                  onPressed: () {
+                    Scaffold.of(context).closeDrawer();
+                  },
+                  child: const Row(
+                    children: [
+                      Text(
+                        'Datenschutz',
+                        style: TextStyle(fontSize: 20),
+                      ),
+                      Spacer(),
+                      Icon(
+                        Icons.privacy_tip,
+                        color: Colors.white,
+                      ),
+                    ],
                   ),
-                ],
-              ),
-            ),
-            TextButton(
-              onPressed: () {
-                Scaffold.of(context).closeDrawer();
-              },
-              child: const Row(
-                children: [
-                  Text(
-                    'Impressum',
-                    style: TextStyle(fontSize: 20),
+                ),
+                TextButton(
+                  onPressed: () {
+                    Scaffold.of(context).closeDrawer();
+                  },
+                  child: const Row(
+                    children: [
+                      Text(
+                        'Impressum',
+                        style: TextStyle(fontSize: 20),
+                      ),
+                      Spacer(),
+                      Icon(
+                        Icons.apartment,
+                        color: Colors.white,
+                      ),
+                    ],
                   ),
-                  Spacer(),
-                  Icon(
-                    Icons.apartment,
-                    color: Colors.white,
+                ),
+                TextButton(
+                  onPressed: () {
+                    value.logout();
+                    // ScaffoldMessenger.of(context).clearSnackBars();
+                    ScaffoldMessenger.of(context).showSnackBar(
+                      _snackBar(
+                        context,
+                        value.response.message != null
+                            ? value.response.message!
+                            : value.response.status.toString(),
+                        value.response.status.toString(),
+                        () {
+                          print('asdf');
+                        },
+                      ),
+                    );
+                  },
+                  child: const Row(
+                    children: [
+                      Text(
+                        'Log out',
+                        style: TextStyle(fontSize: 20),
+                      ),
+                      Spacer(),
+                      Icon(
+                        Icons.logout,
+                        color: Colors.white,
+                      ),
+                    ],
                   ),
-                ],
-              ),
-            ),
-            TextButton(
-              onPressed: () {
-                setState(() {
-                  widget.client.session.accessToken = null;
-                  widget.client.session
-                      .removeSession(widget.client.session.sessionId!);
-                });
-              },
-              child: const Row(
-                children: [
-                  Text(
-                    'Log out',
-                    style: TextStyle(fontSize: 20),
-                  ),
-                  Spacer(),
-                  Icon(
-                    Icons.logout,
-                    color: Colors.white,
-                  ),
-                ],
-              ),
-            ),
-            const SizedBox(
-              height: 250,
-            )
-          ]);
-        }),
-        bottomNavigationBar: Builder(builder: (context) {
-          return BottomBar(
-            // onTap: (value) => _bottomBarAction(value),
-            children: widget.client.session.accessToken != null
-                ? [
-                    BottomNavigationBarItem(
-                      backgroundColor: Colors.white,
-                      label: 'Personen',
-                      icon: Column(
-                        children: [
-                          IconButton(
-                            onPressed: () => Scaffold.of(context).openDrawer(),
+                ),
+                const SizedBox(
+                  height: 250,
+                )
+              ]);
+            }),
+            bottomNavigationBar: Builder(builder: (context) {
+              return BottomBar(
+                // onTap: (value) => _bottomBarAction(value),
+                children: value.response.data != null
+                    ? [
+                        BottomNavigationBarItem(
+                          backgroundColor: Colors.white,
+                          label: 'Personen',
+                          icon: Column(
+                            children: [
+                              IconButton(
+                                onPressed: () =>
+                                    Scaffold.of(context).openDrawer(),
+                                icon: const Icon(
+                                  Icons.group,
+                                  color: Colors.white,
+                                ),
+                              ),
+                              const Text(
+                                'Personen',
+                                style: TextStyle(
+                                  color: Colors.white,
+                                  fontSize: 16,
+                                ),
+                              )
+                            ],
+                          ),
+                        ),
+                        BottomNavigationBarItem(
+                          backgroundColor: Colors.white,
+                          label: 'Dashboard',
+                          icon: Column(
+                            children: [
+                              IconButton(
+                                onPressed: () {},
+                                icon: const Icon(
+                                  Icons.dashboard,
+                                  color: Colors.white,
+                                ),
+                              ),
+                              const Text(
+                                'Dashboard',
+                                style: TextStyle(
+                                  color: Colors.white,
+                                  fontSize: 16,
+                                ),
+                              )
+                            ],
+                          ),
+                        ),
+                        BottomNavigationBarItem(
+                          backgroundColor: Colors.white,
+                          label: 'Menu',
+                          icon: IconButton(
+                            onPressed: () {
+                              Scaffold.of(context).openDrawer();
+                            },
                             icon: const Icon(
-                              Icons.group,
+                              Icons.menu,
                               color: Colors.white,
                             ),
                           ),
-                          const Text(
-                            'Personen',
-                            style: TextStyle(
-                              color: Colors.white,
-                              fontSize: 16,
-                            ),
-                          )
-                        ],
-                      ),
-                    ),
-                    BottomNavigationBarItem(
-                      backgroundColor: Colors.white,
-                      label: 'Dashboard',
-                      icon: Column(
-                        children: [
-                          IconButton(
-                            onPressed: () async {
-                              if (widget.client.session.accessTokenExpiresAt!
-                                  .toDateTime()
-                                  .isBefore(DateTime.now())) {
-                                await widget.client.refreshToken();
-                              }
-                              if (!widget.client.isLoggedIn &&
-                                  context.mounted) {
-                                ScaffoldMessenger.of(context).showSnackBar(
-                                  const SnackBar(
-                                    content: Text('Sitzung ist abgelaufen.'),
-                                  ),
-                                );
-                                if (context.mounted) {
-                                  Navigator.pushAndRemoveUntil(
+                        )
+                      ]
+                    : [
+                        BottomNavigationBarItem(
+                          label: 'register',
+                          backgroundColor: Colors.white,
+                          icon: Column(
+                            children: [
+                              IconButton(
+                                onPressed: () {},
+                                icon: const Icon(
+                                  Icons.login,
+                                  color: Colors.white,
+                                ),
+                              ),
+                              const Text(
+                                'Registrieren',
+                                style: TextStyle(
+                                  color: Colors.white,
+                                  fontSize: 16,
+                                ),
+                              )
+                            ],
+                          ),
+                        ),
+                        BottomNavigationBarItem(
+                          label: 'login',
+                          backgroundColor: Colors.white,
+                          icon: Column(
+                            children: [
+                              IconButton(
+                                onPressed: () {
+                                  Navigator.push(
                                       context,
                                       MaterialPageRoute(
-                                          builder: (context) =>
-                                              LoginPage(client: widget.client)),
-                                      (route) => false);
-                                }
-                              } else {
-                                final ctx = context;
-                                // ignore: use_build_context_synchronously
-                                GClient c = await Navigator.push(
-                                  ctx,
-                                  MaterialPageRoute(
-                                    builder: (context) => DashboardPage(
-                                      client: widget.client,
-                                    ),
-                                  ),
-                                );
-                                _updateClient(c);
-                              }
-                            },
+                                          builder: (builder) =>
+                                              const LoginPage()));
+                                },
+                                icon: const Icon(
+                                  Icons.login,
+                                  color: Colors.white,
+                                ),
+                              ),
+                              const Text(
+                                'Login',
+                                style: TextStyle(
+                                  color: Colors.white,
+                                  fontSize: 16,
+                                ),
+                              )
+                            ],
+                          ),
+                        ),
+                        BottomNavigationBarItem(
+                          backgroundColor: Colors.white,
+                          label: 'Menu',
+                          icon: IconButton(
+                            onPressed: () => Scaffold.of(context).openDrawer(),
                             icon: const Icon(
-                              Icons.dashboard,
+                              Icons.menu,
                               color: Colors.white,
                             ),
                           ),
+                        ),
+                      ],
+              );
+            }),
+            body: Column(
+              children: [
+                if (value.response.status == Status.COMPLETED &&
+                    value.response.data != null &&
+                    !(value.response.data as Account).emailVerified)
+                  Card(
+                    color: Colors.orange,
+                    child: Center(
+                      child: Row(
+                        mainAxisAlignment: MainAxisAlignment.spaceAround,
+                        children: [
                           const Text(
-                            'Dashboard',
+                            'E-Mail ist noch nicht verifiziert.',
                             style: TextStyle(
+                                fontWeight: FontWeight.bold,
+                                fontFamily: 'sans-serif',
+                                fontSize: 14),
+                          ),
+                          IconButton(
+                            onPressed: () {},
+                            icon: const Icon(
+                              Icons.restore,
                               color: Colors.white,
-                              fontSize: 16,
                             ),
-                          )
+                          ),
                         ],
                       ),
                     ),
-                    BottomNavigationBarItem(
-                      backgroundColor: Colors.white,
-                      label: 'Menu',
-                      icon: IconButton(
-                        onPressed: () {
-                          Scaffold.of(context).openDrawer();
-                        },
-                        icon: const Icon(
-                          Icons.menu,
-                          color: Colors.white,
+                  ),
+                Padding(
+                  padding: const EdgeInsets.all(16.0),
+                  child: Column(
+                    mainAxisAlignment: MainAxisAlignment.center,
+                    children: [
+                      const Image(
+                        image: AssetImage(
+                          'lib/assets/logo_300x200.png',
                         ),
                       ),
-                    )
-                  ]
-                : [
-                    BottomNavigationBarItem(
-                      label: 'register',
-                      backgroundColor: Colors.white,
-                      icon: Column(
-                        children: [
-                          IconButton(
-                            onPressed: () async {
-                              widget.client = await Navigator.push(
-                                  context,
-                                  MaterialPageRoute(
-                                      builder: (context) => RegisterPage(
-                                            client: widget.client,
-                                          )));
-                            },
-                            icon: const Icon(
-                              Icons.login,
-                              color: Colors.white,
-                            ),
-                          ),
-                          const Text(
-                            'Registrieren',
-                            style: TextStyle(
-                              color: Colors.white,
-                              fontSize: 16,
-                            ),
-                          )
-                        ],
+                      const SizedBox(
+                        height: 40,
                       ),
-                    ),
-                    BottomNavigationBarItem(
-                      label: 'login',
-                      backgroundColor: Colors.white,
-                      icon: Column(
-                        children: [
-                          IconButton(
-                            onPressed: () async {
-                              final c = await Navigator.push(
-                                  context,
-                                  MaterialPageRoute(
-                                    builder: (context) => LoginPage(
-                                      client: widget.client,
-                                    ),
-                                  ));
-                              _updateClient(c);
-                            },
-                            icon: const Icon(
-                              Icons.login,
-                              color: Colors.white,
-                            ),
-                          ),
-                          const Text(
-                            'Login',
-                            style: TextStyle(
-                              color: Colors.white,
-                              fontSize: 16,
-                            ),
-                          )
-                        ],
-                      ),
-                    ),
-                    BottomNavigationBarItem(
-                      backgroundColor: Colors.white,
-                      label: 'Menu',
-                      icon: IconButton(
-                        onPressed: () => Scaffold.of(context).openDrawer(),
-                        icon: const Icon(
-                          Icons.menu,
-                          color: Colors.white,
+                      Text(
+                        'Digitale Spuren auf Knopfdruck entfernen'
+                            .toUpperCase(),
+                        textAlign: TextAlign.center,
+                        style: const TextStyle(
+                          fontFamily: 'sans-serif',
+                          fontSize: 24,
+                          height: 1.6,
+                          fontWeight: FontWeight.normal,
+                          letterSpacing: 6,
                         ),
                       ),
-                    ),
-                  ],
-          );
-        }),
-        body: Padding(
-          padding: const EdgeInsets.all(16.0),
-          child: Column(
-            mainAxisAlignment: MainAxisAlignment.center,
-            children: [
-              const Image(
-                image: AssetImage(
-                  'lib/assets/logo_300x200.png',
-                ),
-              ),
-              if (widget.client.account != null &&
-                  !widget.client.account!.emailVerified)
-                Container(
-                  height: 120,
-                  width: double.infinity,
-                  padding:
-                      const EdgeInsets.symmetric(vertical: 20, horizontal: 10),
-                  child: Card(
-                    color: Colors.brown.shade300,
-                    child: const Text(
-                        'Deine E-Mail Adresse ist noch nicht validiert.'),
+                      TextButton(
+                          onPressed: () {
+                            // ScaffoldMessenger.of(context).clearSnackBars();
+                            ScaffoldMessenger.of(context).showSnackBar(
+                              _snackBar(
+                                context,
+                                value.response.message != null
+                                    ? value.response.message!
+                                    : value.response.status.toString(),
+                                value.response.status.toString(),
+                                () {
+                                  print('asdf');
+                                },
+                              ),
+                            );
+                          },
+                          child: const Text('asdf'))
+                    ],
                   ),
                 ),
-              const SizedBox(
-                height: 40,
-              ),
-              Text(
-                'Digitale Spuren auf Knopfdruck entfernen'.toUpperCase(),
-                textAlign: TextAlign.center,
-                style: const TextStyle(
-                  fontFamily: 'sans-serif',
-                  fontSize: 24,
-                  height: 1.6,
-                  fontWeight: FontWeight.normal,
-                  letterSpacing: 6,
-                ),
-              ),
-            ],
-          ),
-        ),
+              ],
+            ),
+          );
+        }),
       ),
     );
   }
diff --git a/frontend/app/pubspec.lock b/frontend/app/pubspec.lock
index 9323a01..112b12d 100644
--- a/frontend/app/pubspec.lock
+++ b/frontend/app/pubspec.lock
@@ -195,6 +195,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.9.1"
+  nested:
+    dependency: transitive
+    description:
+      name: nested
+      sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.0"
   path:
     dependency: "direct main"
     description:
@@ -219,6 +227,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "3.1.0"
+  provider:
+    dependency: "direct main"
+    description:
+      name: provider
+      sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f
+      url: "https://pub.dev"
+    source: hosted
+    version: "6.0.5"
   sky_engine:
     dependency: transitive
     description: flutter
diff --git a/frontend/app/pubspec.yaml b/frontend/app/pubspec.yaml
index f28d267..2960757 100644
--- a/frontend/app/pubspec.yaml
+++ b/frontend/app/pubspec.yaml
@@ -42,6 +42,7 @@ dependencies:
   sqflite: ^2.3.0
   path: ^1.8.3
   fixnum: ^1.1.0
+  provider: ^6.0.5
 
 dev_dependencies:
   lints: ^2.0.0

From 7750972a421477070f8b92a2caa6a5ed13cc555f Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Sat, 4 Nov 2023 01:44:49 +0100
Subject: [PATCH 21/24] rf/replaces home_screen and login backs up old screens
 to pages_old

---
 frontend/app/lib/data/database.dart           |  10 +-
 frontend/app/lib/main.dart                    |  10 +-
 .../lib/model/services/backend_service.dart   |  10 +-
 frontend/app/lib/pages/home_page.dart         | 160 ++++++++++++++++++
 frontend/app/lib/pages/login_overlay.dart     | 134 +++++++++++++++
 frontend/app/lib/pages/pages.dart             |   1 -
 .../{pages => pages_old}/dashboard_page.dart  |   2 +-
 .../lib/{pages => pages_old}/login_page.dart  |   2 +-
 .../{pages => pages_old}/register_page.dart   |   2 +-
 .../lib/{pages => pages_old}/start_page.dart  |   6 +-
 .../app/lib/widgets/bottom_navigation.dart    |  48 ++++++
 .../lib/widgets/bottom_navigation_item.dart   |  45 +++++
 frontend/app/lib/widgets/drawer.dart          |  31 ++++
 .../app/lib/widgets/side_drawer_item.dart     |  50 ++++++
 14 files changed, 490 insertions(+), 21 deletions(-)
 create mode 100644 frontend/app/lib/pages/home_page.dart
 create mode 100644 frontend/app/lib/pages/login_overlay.dart
 delete mode 100644 frontend/app/lib/pages/pages.dart
 rename frontend/app/lib/{pages => pages_old}/dashboard_page.dart (99%)
 rename frontend/app/lib/{pages => pages_old}/login_page.dart (99%)
 rename frontend/app/lib/{pages => pages_old}/register_page.dart (99%)
 rename frontend/app/lib/{pages => pages_old}/start_page.dart (98%)
 create mode 100644 frontend/app/lib/widgets/bottom_navigation.dart
 create mode 100644 frontend/app/lib/widgets/bottom_navigation_item.dart
 create mode 100644 frontend/app/lib/widgets/drawer.dart
 create mode 100644 frontend/app/lib/widgets/side_drawer_item.dart

diff --git a/frontend/app/lib/data/database.dart b/frontend/app/lib/data/database.dart
index 7d7e411..1ae9a7f 100644
--- a/frontend/app/lib/data/database.dart
+++ b/frontend/app/lib/data/database.dart
@@ -14,9 +14,7 @@ class Session {
     this.refreshToken,
     this.refreshTokenExpiresAt,
     this.accountId,
-  }) {
-    _init();
-  }
+  });
 
   String? sessionId;
   String? accessToken;
@@ -169,12 +167,14 @@ class Session {
     final db = await database;
 
     final List<Map<String, Object?>> maps = await db.query('sessions');
-
+    print(maps);
     final List<Session> sessions = List.generate(
       maps.length,
       (i) {
         // print('GOT MAP: ${maps[i]}');
-
+        if (maps[i]['sessionId'] == null) {
+          return Session();
+        }
         return Session(
           sessionId: maps[i]['sessionId'] as String,
           accessToken: maps[i]['accessToken'] as String,
diff --git a/frontend/app/lib/main.dart b/frontend/app/lib/main.dart
index e790121..14f789a 100644
--- a/frontend/app/lib/main.dart
+++ b/frontend/app/lib/main.dart
@@ -1,6 +1,4 @@
-import 'package:app/gapi/client.dart';
-import 'package:app/pages/start_page.dart';
-import 'package:app/widgets/background.dart';
+import 'package:app/pages/home_page.dart';
 import 'package:flutter/material.dart';
 
 void main() async {
@@ -43,11 +41,7 @@ void main() async {
             backgroundColor: Colors.black,
             foregroundColor: Colors.white,
           )),
-      home: Background(
-        child: StartPage(
-            // client: await GClient.client,
-            ),
-      ),
+      home: const HomePage(),
     ),
   );
 }
diff --git a/frontend/app/lib/model/services/backend_service.dart b/frontend/app/lib/model/services/backend_service.dart
index 6cc42d0..f67b83d 100644
--- a/frontend/app/lib/model/services/backend_service.dart
+++ b/frontend/app/lib/model/services/backend_service.dart
@@ -202,7 +202,15 @@ class BackendService {
           password: password,
         ),
       );
-      await Session.newSession(response as Session);
+      Session s = Session(
+        accessToken: response.accessToken,
+        sessionId: response.sessionId,
+        accessTokenExpiresAt: response.accessTokenExpiresAt,
+        refreshToken: response.refreshToken,
+        refreshTokenExpiresAt: response.refreshTokenExpiresAt,
+        accountId: response.accountId,
+      );
+      await Session.newSession(s);
       return response.accessToken != '';
     } on SocketException {
       throw FetchDataException('Keine Internet Verbindung');
diff --git a/frontend/app/lib/pages/home_page.dart b/frontend/app/lib/pages/home_page.dart
new file mode 100644
index 0000000..d34c4d6
--- /dev/null
+++ b/frontend/app/lib/pages/home_page.dart
@@ -0,0 +1,160 @@
+import 'dart:io';
+
+import 'package:app/model/services/backend_service.dart';
+import 'package:app/model/view_model/account_vm.dart';
+import 'package:app/pages/login_overlay.dart';
+import 'package:app/widgets/background.dart';
+import 'package:app/widgets/bottom_navigation.dart';
+import 'package:app/widgets/bottom_navigation_item.dart';
+import 'package:app/widgets/drawer.dart';
+import 'package:app/widgets/side_drawer_item.dart';
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+
+class HomePage extends StatefulWidget {
+  const HomePage({super.key});
+
+  @override
+  State<HomePage> createState() => _HomePageState();
+}
+
+class _HomePageState extends State<HomePage> {
+  @override
+  void initState() {
+    super.initState();
+    _init();
+  }
+
+  void _init() async {
+    _setLoading(true);
+    _loggedin = await BackendService.isLoggedIn;
+    _setLoading(false);
+  }
+
+  void _setLoading(bool loading) {
+    setState(() {
+      _loading = loading;
+    });
+  }
+
+  bool _loading = true;
+  bool _loggedin = false;
+  @override
+  Widget build(BuildContext context) {
+    return Background(
+      child: ChangeNotifierProvider<AccountViewModel>(
+        create: (context) => AccountViewModel(),
+        child: Consumer<AccountViewModel>(
+          builder: (context, value, child) => Scaffold(
+            appBar: AppBar(
+              automaticallyImplyLeading: false,
+              // flexibleSpace: Image.asset(
+              //   'lib/assets/logo_300x200.png',
+              //   // height: 400,
+              // ),
+            ),
+            drawer: SideDrawer(
+              children: [
+                const Spacer(
+                  flex: 3,
+                ),
+                SideDrawerItem(
+                  onPressed: () {},
+                  icon: Icons.question_answer,
+                  color: Colors.white,
+                  label: 'About',
+                ),
+                SideDrawerItem(
+                  onPressed: () {},
+                  icon: Icons.privacy_tip,
+                  color: Colors.white,
+                  label: 'Datenschutz',
+                ),
+                SideDrawerItem(
+                  onPressed: () {},
+                  icon: Icons.apartment,
+                  color: Colors.white,
+                  label: 'Impressum',
+                ),
+                const Spacer(
+                  flex: 1,
+                ),
+                if (_loggedin || value.response.data != null)
+                  SideDrawerItem(
+                    onPressed: () {},
+                    icon: Icons.logout,
+                    color: Colors.white,
+                    label: 'Logout',
+                  ),
+              ],
+            ),
+            bottomNavigationBar: BottomNavigation(
+              children: [
+                if (!_loggedin) ...[
+                  BottomNavigationItem(
+                    onPressed: () {},
+                    icon: Icons.person_add_alt,
+                    color: Colors.white,
+                    label: 'Registrieren',
+                  ),
+                  BottomNavigationItem(
+                    onPressed: () async {
+                      _loggedin = await showLogin(context);
+                    },
+                    icon: Icons.login,
+                    color: Colors.white,
+                    label: 'Login',
+                  ),
+                ] else
+                  BottomNavigationItem(
+                    onPressed: () {},
+                    icon: Icons.person_search,
+                    color: Colors.white,
+                    label: 'Personen',
+                  ),
+                BottomNavigationItem(
+                  onPressed: () {},
+                  icon: Icons.dashboard,
+                  color: Colors.white,
+                  label: 'Dashboard',
+                ),
+                ...[]
+              ],
+            ),
+            body: Padding(
+              padding: const EdgeInsets.fromLTRB(16, 40, 16, 16),
+              child: Center(
+                child: _loading
+                    ? const CircularProgressIndicator(
+                        color: Colors.grey,
+                      )
+                    : Column(
+                        children: [
+                          Image.asset(
+                            'lib/assets/logo_300x200.png',
+                          ),
+                          const SizedBox(
+                            height: 40,
+                          ),
+                          Text(
+                            'Digitale Spuren auf Knopfdruck entfernen'
+                                .toUpperCase(),
+                            textAlign: TextAlign.center,
+                            style: const TextStyle(
+                              fontFamily: 'sans-serif',
+                              fontSize: 24,
+                              height: 1.6,
+                              fontWeight: FontWeight.normal,
+                              letterSpacing: 6,
+                            ),
+                          ),
+                        ],
+                      ),
+              ),
+            ),
+          ),
+        ),
+      ),
+    );
+  }
+}
diff --git a/frontend/app/lib/pages/login_overlay.dart b/frontend/app/lib/pages/login_overlay.dart
new file mode 100644
index 0000000..21e265f
--- /dev/null
+++ b/frontend/app/lib/pages/login_overlay.dart
@@ -0,0 +1,134 @@
+import 'package:app/model/services/backend_service.dart';
+import 'package:app/widgets/background.dart';
+import 'package:flutter/material.dart';
+
+Future<bool> showLogin(BuildContext context) async {
+  final _formKey = GlobalKey<FormState>();
+  final mailController = TextEditingController();
+  final passwordController = TextEditingController();
+
+  bool _loggedin = false;
+
+  await showModalBottomSheet(
+      useSafeArea: true,
+      isScrollControlled: true,
+      backgroundColor: Colors.black,
+      context: context,
+      builder: (builder) {
+        return Background(
+          child: Column(
+            mainAxisAlignment: MainAxisAlignment.center,
+            children: [
+              const SizedBox(
+                height: 50,
+              ),
+              const Image(
+                width: 180,
+                image: AssetImage(
+                  'lib/assets/logo_300x200.png',
+                ),
+              ),
+              const SizedBox(
+                height: 30,
+              ),
+              const Text(
+                'Login',
+                style: TextStyle(
+                  fontFamily: 'sans-serif',
+                  fontSize: 24,
+                  height: 1.6,
+                  fontWeight: FontWeight.normal,
+                  letterSpacing: 6,
+                ),
+              ),
+              Form(
+                key: _formKey,
+                child: Column(
+                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+                  crossAxisAlignment: CrossAxisAlignment.center,
+                  children: [
+                    const SizedBox(
+                      height: 40,
+                    ),
+                    TextFormField(
+                      controller: mailController,
+                      decoration: const InputDecoration(
+                        fillColor: Color.fromARGB(30, 255, 255, 255),
+                        filled: true,
+                        hintStyle: TextStyle(
+                          color: Colors.white38,
+                        ),
+                        hintText: 'E-Mail Adresse',
+                      ),
+                      keyboardType: TextInputType.emailAddress,
+                      validator: (value) {
+                        if (value == null || value.isEmpty) {
+                          return 'Bitte eine gültige E-Mail Adresse eingeben';
+                        }
+                        return null;
+                      },
+                    ),
+                    TextFormField(
+                      style: const TextStyle(
+                        color: Colors.white,
+                      ),
+                      controller: passwordController,
+                      decoration: const InputDecoration(
+                        fillColor: Color.fromARGB(30, 255, 255, 255),
+                        filled: true,
+                        hintStyle: TextStyle(
+                          color: Colors.white38,
+                        ),
+                        hintText: 'Passwort',
+                      ),
+                      keyboardType: TextInputType.visiblePassword,
+                      obscureText: true,
+                      validator: (value) {
+                        if (value == null || value.isEmpty) {
+                          return 'Bitte geben Sie Ihr Passwort ein';
+                        }
+                        return null;
+                      },
+                    ),
+                    const SizedBox(
+                      height: 15,
+                    ),
+                    Row(
+                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+                      children: [
+                        ElevatedButton(
+                          onPressed: () {
+                            Navigator.pop(context);
+                          },
+                          child: const Icon(Icons.arrow_back),
+                        ),
+                        ElevatedButton(
+                          onPressed: () {
+                            if (_formKey.currentState!.validate()) {
+                              BackendService.login(
+                                email: mailController.text,
+                                password: passwordController.text,
+                              ).then(
+                                (r) {
+                                  if (r) {
+                                    _loggedin = r;
+                                    Navigator.pop(context, true);
+                                  }
+                                },
+                              );
+                            }
+                          },
+                          child: const Icon(Icons.login),
+                        ),
+                      ],
+                    )
+                  ],
+                ),
+              ),
+              const Spacer(),
+            ],
+          ),
+        );
+      });
+  return _loggedin;
+}
diff --git a/frontend/app/lib/pages/pages.dart b/frontend/app/lib/pages/pages.dart
deleted file mode 100644
index 6db3efe..0000000
--- a/frontend/app/lib/pages/pages.dart
+++ /dev/null
@@ -1 +0,0 @@
-enum Pages { start, login, about, persons, dashboard }
diff --git a/frontend/app/lib/pages/dashboard_page.dart b/frontend/app/lib/pages_old/dashboard_page.dart
similarity index 99%
rename from frontend/app/lib/pages/dashboard_page.dart
rename to frontend/app/lib/pages_old/dashboard_page.dart
index 14d3a25..3c8503b 100644
--- a/frontend/app/lib/pages/dashboard_page.dart
+++ b/frontend/app/lib/pages_old/dashboard_page.dart
@@ -1,5 +1,5 @@
 import 'package:app/gapi/client.dart';
-import 'package:app/pages/start_page.dart';
+import 'package:app/pages_old/start_page.dart';
 import 'package:app/pb/account_info.pb.dart';
 import 'package:app/pb/rpc_get_account_info.pb.dart';
 import 'package:app/widgets/background.dart';
diff --git a/frontend/app/lib/pages/login_page.dart b/frontend/app/lib/pages_old/login_page.dart
similarity index 99%
rename from frontend/app/lib/pages/login_page.dart
rename to frontend/app/lib/pages_old/login_page.dart
index b7d49d2..d2207e7 100644
--- a/frontend/app/lib/pages/login_page.dart
+++ b/frontend/app/lib/pages_old/login_page.dart
@@ -1,6 +1,6 @@
 import 'package:app/gapi/client.dart';
 import 'package:app/model/services/backend_service.dart';
-import 'package:app/pages/start_page.dart';
+import 'package:app/pages_old/start_page.dart';
 import 'package:app/widgets/background.dart';
 import 'package:app/widgets/bottom_bar.dart';
 import 'package:app/widgets/loading_widget.dart';
diff --git a/frontend/app/lib/pages/register_page.dart b/frontend/app/lib/pages_old/register_page.dart
similarity index 99%
rename from frontend/app/lib/pages/register_page.dart
rename to frontend/app/lib/pages_old/register_page.dart
index d5ee106..2a40fd6 100644
--- a/frontend/app/lib/pages/register_page.dart
+++ b/frontend/app/lib/pages_old/register_page.dart
@@ -1,5 +1,5 @@
 import 'package:app/gapi/client.dart';
-import 'package:app/pages/start_page.dart';
+import 'package:app/pages_old/start_page.dart';
 import 'package:app/widgets/background.dart';
 import 'package:app/widgets/bottom_bar.dart';
 import 'package:app/widgets/loading_widget.dart';
diff --git a/frontend/app/lib/pages/start_page.dart b/frontend/app/lib/pages_old/start_page.dart
similarity index 98%
rename from frontend/app/lib/pages/start_page.dart
rename to frontend/app/lib/pages_old/start_page.dart
index 39d6ecf..6235c2c 100644
--- a/frontend/app/lib/pages/start_page.dart
+++ b/frontend/app/lib/pages_old/start_page.dart
@@ -1,9 +1,9 @@
 import 'package:app/gapi/client.dart';
 import 'package:app/model/apis/api_response.dart';
 import 'package:app/model/view_model/account_vm.dart';
-import 'package:app/pages/dashboard_page.dart';
-import 'package:app/pages/login_page.dart';
-import 'package:app/pages/register_page.dart';
+import 'package:app/pages_old/dashboard_page.dart';
+import 'package:app/pages_old/login_page.dart';
+import 'package:app/pages_old/register_page.dart';
 import 'package:app/pb/account.pb.dart';
 import 'package:app/widgets/background.dart';
 import 'package:app/widgets/bottom_bar.dart';
diff --git a/frontend/app/lib/widgets/bottom_navigation.dart b/frontend/app/lib/widgets/bottom_navigation.dart
new file mode 100644
index 0000000..25e74b9
--- /dev/null
+++ b/frontend/app/lib/widgets/bottom_navigation.dart
@@ -0,0 +1,48 @@
+import 'package:flutter/material.dart';
+
+class BottomNavigation extends StatelessWidget {
+  BottomNavigation({
+    super.key,
+    required this.children,
+    this.backgroundColor,
+    this.iconColor,
+  }) {
+    backgroundColor ??= Colors.black;
+  }
+
+  List<Widget> children;
+  Color? backgroundColor;
+  Color? iconColor;
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      height: 70,
+      color: backgroundColor,
+      child: Center(
+        child: Padding(
+          padding: const EdgeInsets.symmetric(
+              // horizontal: 10,
+              ),
+          child: Row(
+            mainAxisAlignment: children.isEmpty
+                ? MainAxisAlignment.center
+                : MainAxisAlignment.spaceAround,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              ...children,
+              Builder(builder: (context) {
+                return IconButton(
+                    onPressed: () => Scaffold.of(context).openDrawer(),
+                    icon: const Icon(
+                      Icons.menu,
+                      color: Colors.white,
+                    ));
+              }),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+}
diff --git a/frontend/app/lib/widgets/bottom_navigation_item.dart b/frontend/app/lib/widgets/bottom_navigation_item.dart
new file mode 100644
index 0000000..72f46c3
--- /dev/null
+++ b/frontend/app/lib/widgets/bottom_navigation_item.dart
@@ -0,0 +1,45 @@
+import 'package:flutter/material.dart';
+
+class BottomNavigationItem extends StatelessWidget {
+  BottomNavigationItem({
+    super.key,
+    required this.onPressed,
+    required this.icon,
+    required this.color,
+    this.textSize,
+    this.iconSize,
+    this.label,
+  }) {
+    textSize ??= 15;
+    iconSize ??= 25;
+  }
+
+  void Function() onPressed;
+  IconData icon;
+  Color color;
+  double? textSize;
+  double? iconSize;
+  String? label;
+
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      mainAxisAlignment:
+          label != null ? MainAxisAlignment.center : MainAxisAlignment.center,
+      children: [
+        IconButton(
+            onPressed: onPressed,
+            icon: Icon(
+              icon,
+              size: iconSize,
+              color: color,
+            )),
+        if (label != null)
+          Text(
+            label!,
+            style: TextStyle(fontSize: textSize, color: color),
+          ),
+      ],
+    );
+  }
+}
diff --git a/frontend/app/lib/widgets/drawer.dart b/frontend/app/lib/widgets/drawer.dart
new file mode 100644
index 0000000..5ec955b
--- /dev/null
+++ b/frontend/app/lib/widgets/drawer.dart
@@ -0,0 +1,31 @@
+import 'package:app/pages/home_page.dart';
+import 'package:app/widgets/side_drawer_item.dart';
+import 'package:flutter/material.dart';
+
+class SideDrawer extends StatelessWidget {
+  SideDrawer({super.key, required this.children, this.backgroundColor}) {
+    backgroundColor ??= Colors.black;
+  }
+
+  List<Widget> children;
+  Color? backgroundColor;
+
+  @override
+  Widget build(BuildContext context) {
+    return Drawer(
+      backgroundColor: backgroundColor,
+      child: Padding(
+        padding: const EdgeInsets.all(40.0),
+        child: Center(
+          child: Builder(builder: (context) {
+            return Column(
+              mainAxisAlignment: MainAxisAlignment.center,
+              crossAxisAlignment: CrossAxisAlignment.start,
+              children: children,
+            );
+          }),
+        ),
+      ),
+    );
+  }
+}
diff --git a/frontend/app/lib/widgets/side_drawer_item.dart b/frontend/app/lib/widgets/side_drawer_item.dart
new file mode 100644
index 0000000..35668a4
--- /dev/null
+++ b/frontend/app/lib/widgets/side_drawer_item.dart
@@ -0,0 +1,50 @@
+import 'package:app/pages/home_page.dart';
+import 'package:flutter/material.dart';
+
+class SideDrawerItem extends StatelessWidget {
+  SideDrawerItem({
+    super.key,
+    required this.onPressed,
+    required this.icon,
+    required this.color,
+    required this.label,
+    this.textSize,
+    this.iconSize,
+  }) {
+    textSize ??= 15;
+    iconSize ??= 25;
+  }
+
+  void Function() onPressed;
+  IconData icon;
+  Color color;
+  String label;
+  double? textSize;
+  double? iconSize;
+
+  @override
+  Widget build(BuildContext context) {
+    return TextButton(
+      onPressed: onPressed,
+      child: Row(
+        // mainAxisAlignment: MainAxisAlignment.start,
+        children: [
+          Icon(
+            icon,
+            color: color,
+          ),
+          const SizedBox(
+            width: 20,
+          ),
+          Text(
+            label,
+            style: TextStyle(
+              fontSize: textSize,
+              color: color,
+            ),
+          )
+        ],
+      ),
+    );
+  }
+}

From ef7f6c093f68ba5feb0c97247212dcf1d6bb00fc Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Sat, 4 Nov 2023 01:58:15 +0100
Subject: [PATCH 22/24] ft/disables buttons on submit

---
 frontend/app/lib/pages/login_overlay.dart | 49 +++++++++++++----------
 1 file changed, 27 insertions(+), 22 deletions(-)

diff --git a/frontend/app/lib/pages/login_overlay.dart b/frontend/app/lib/pages/login_overlay.dart
index 21e265f..6d59622 100644
--- a/frontend/app/lib/pages/login_overlay.dart
+++ b/frontend/app/lib/pages/login_overlay.dart
@@ -3,11 +3,28 @@ import 'package:app/widgets/background.dart';
 import 'package:flutter/material.dart';
 
 Future<bool> showLogin(BuildContext context) async {
-  final _formKey = GlobalKey<FormState>();
+  final formKey = GlobalKey<FormState>();
   final mailController = TextEditingController();
   final passwordController = TextEditingController();
 
-  bool _loggedin = false;
+  bool submitted = false;
+  bool loggedin = false;
+  void login() {
+    if (formKey.currentState!.validate()) {
+      submitted = true;
+      BackendService.login(
+        email: mailController.text,
+        password: passwordController.text,
+      ).then(
+        (r) {
+          if (r) {
+            loggedin = r;
+            Navigator.pop(context, true);
+          }
+        },
+      );
+    }
+  }
 
   await showModalBottomSheet(
       useSafeArea: true,
@@ -42,7 +59,7 @@ Future<bool> showLogin(BuildContext context) async {
                 ),
               ),
               Form(
-                key: _formKey,
+                key: formKey,
                 child: Column(
                   mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                   crossAxisAlignment: CrossAxisAlignment.center,
@@ -97,27 +114,15 @@ Future<bool> showLogin(BuildContext context) async {
                       mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                       children: [
                         ElevatedButton(
-                          onPressed: () {
-                            Navigator.pop(context);
-                          },
+                          onPressed: !submitted
+                              ? () {
+                                  Navigator.pop(context);
+                                }
+                              : null,
                           child: const Icon(Icons.arrow_back),
                         ),
                         ElevatedButton(
-                          onPressed: () {
-                            if (_formKey.currentState!.validate()) {
-                              BackendService.login(
-                                email: mailController.text,
-                                password: passwordController.text,
-                              ).then(
-                                (r) {
-                                  if (r) {
-                                    _loggedin = r;
-                                    Navigator.pop(context, true);
-                                  }
-                                },
-                              );
-                            }
-                          },
+                          onPressed: !submitted ? login : null,
                           child: const Icon(Icons.login),
                         ),
                       ],
@@ -130,5 +135,5 @@ Future<bool> showLogin(BuildContext context) async {
           ),
         );
       });
-  return _loggedin;
+  return loggedin;
 }

From 604c2bdd270b57334114a7c40387c482f57f634c Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Sun, 5 Nov 2023 22:41:38 +0100
Subject: [PATCH 23/24] ft/adds auto logout and persons_page

---
 .../lib/model/services/backend_service.dart   |  65 ++++-
 .../app/lib/model/view_model/persons_vm.dart  |  29 +++
 frontend/app/lib/pages/home_page.dart         | 244 +++++++++++-------
 frontend/app/lib/pages/login_overlay.dart     |  48 +++-
 frontend/app/lib/pages/persons_page.dart      | 174 +++++++++++++
 frontend/app/lib/util/validation.dart         |  27 ++
 6 files changed, 478 insertions(+), 109 deletions(-)
 create mode 100644 frontend/app/lib/model/view_model/persons_vm.dart
 create mode 100644 frontend/app/lib/pages/persons_page.dart
 create mode 100644 frontend/app/lib/util/validation.dart

diff --git a/frontend/app/lib/model/services/backend_service.dart b/frontend/app/lib/model/services/backend_service.dart
index f67b83d..669bc3e 100644
--- a/frontend/app/lib/model/services/backend_service.dart
+++ b/frontend/app/lib/model/services/backend_service.dart
@@ -5,9 +5,11 @@ import 'package:app/pb/account.pb.dart';
 import 'package:app/pb/account_info.pb.dart';
 import 'package:app/pb/person.pb.dart';
 import 'package:app/data/database.dart';
+import 'package:app/pb/rpc_create_account.pb.dart';
 import 'package:app/pb/rpc_get_account.pb.dart';
 import 'package:app/pb/rpc_get_account_info.pb.dart';
 import 'package:app/pb/rpc_get_person.pb.dart';
+import 'package:app/pb/rpc_list_persons.pb.dart';
 import 'package:app/pb/rpc_login.pb.dart';
 import 'package:app/pb/rpc_refresh_token.pb.dart';
 import 'package:app/pb/service_df.pbgrpc.dart';
@@ -87,20 +89,48 @@ class BackendService {
     }
 
     if (session.accessTokenExpiresAt == null) {
+      await logout();
       return false;
     }
 
     if (session.refreshTokenExpiresAt == null) {
+      await logout();
       return false;
     }
 
     if (session.refreshTokenExpiresAt!.toDateTime().isBefore(DateTime.now())) {
+      await logout();
       return false;
     }
 
+    if (session.accessTokenExpiresAt!.toDateTime().isBefore(DateTime.now())) {
+      Session s = await BackendService.refreshToken(session);
+      if (s == session) {
+        return false;
+      }
+    }
+
     return true;
   }
 
+  static Future<bool> createAccount(
+      {required String email, required String password}) async {
+    try {
+      await BackendService.client.createAccount(CreateAccountRequest(
+        email: email,
+        password: password,
+      ));
+
+      return await login(email: email, password: password);
+    } on SocketException {
+      throw FetchDataException('Keine Internet Verbindung');
+    } on GrpcError catch (err) {
+      throw FetchDataException(err.message);
+    } catch (err) {
+      throw InternalException(err.toString());
+    }
+  }
+
   Future<Account> getAccount() async {
     Session? session = await _isLoggedIn();
     if (session == null) {
@@ -177,6 +207,34 @@ class BackendService {
     }
   }
 
+  Future<List<Person>> listPersons() async {
+    Session session = await Session.session;
+    if (session.accessTokenExpiresAt == null) {
+      throw UnauthorizedException('Keine Siztung gefunden');
+    }
+    if (session.accessTokenExpiresAt!.toDateTime().isBefore(DateTime.now())) {
+      session = await refreshToken(session);
+      if (session.accessTokenExpiresAt == null) {
+        throw UnauthorizedException('Sitzung ist abgelaufen');
+      }
+    }
+    try {
+      final ListPersonsResponse response = await _client.listPersons(
+          ListPersonsRequest(
+            accountId: session.accountId,
+          ),
+          options: CallOptions(
+              metadata: {'Authorization': 'Bearer ${session.accessToken}'}));
+      return response.persons;
+    } on SocketException {
+      throw FetchDataException('Keine Internet Verbindung');
+    } on GrpcError catch (err) {
+      throw FetchDataException(err.message);
+    } catch (err) {
+      throw InternalException(err.toString());
+    }
+  }
+
   // Future<List<Person>> listPersons() async {
   //   if (_session.accessToken == null) {
   //     refreshToken();
@@ -221,10 +279,11 @@ class BackendService {
     }
   }
 
-  Future<Session> refreshToken(Session session) async {
+  static Future<Session> refreshToken(Session session) async {
     try {
-      final RefreshTokenResponse response = await _client.refreshToken(
-          RefreshTokenRequest(refreshToken: session.refreshToken));
+      final RefreshTokenResponse response = await BackendService.client
+          .refreshToken(
+              RefreshTokenRequest(refreshToken: session.refreshToken));
       session.accessToken = response.accessToken;
       session.accessTokenExpiresAt = response.accessTokenExpiresAt;
       session = await Session.updateToken(session);
diff --git a/frontend/app/lib/model/view_model/persons_vm.dart b/frontend/app/lib/model/view_model/persons_vm.dart
new file mode 100644
index 0000000..40e4606
--- /dev/null
+++ b/frontend/app/lib/model/view_model/persons_vm.dart
@@ -0,0 +1,29 @@
+import 'package:app/model/apis/api_response.dart';
+import 'package:app/model/services/backend_service.dart';
+import 'package:app/pb/account.pb.dart';
+import 'package:app/pb/person.pb.dart';
+import 'package:flutter/material.dart';
+
+class PersonsViewModel with ChangeNotifier {
+  PersonsViewModel() {
+    listPersons();
+  }
+  ApiResponse _apiResponse = ApiResponse.initial('Keine Daten');
+
+  final BackendService _service = BackendService();
+
+  ApiResponse get response {
+    return _apiResponse;
+  }
+
+  void listPersons() async {
+    _apiResponse = ApiResponse.loading('Bereite alles vor');
+    try {
+      _apiResponse =
+          ApiResponse.completed(await _service.listPersons(), 'done');
+    } catch (e) {
+      _apiResponse = ApiResponse.error(e.toString());
+    }
+    notifyListeners();
+  }
+}
diff --git a/frontend/app/lib/pages/home_page.dart b/frontend/app/lib/pages/home_page.dart
index d34c4d6..c2eb137 100644
--- a/frontend/app/lib/pages/home_page.dart
+++ b/frontend/app/lib/pages/home_page.dart
@@ -1,8 +1,8 @@
-import 'dart:io';
-
+import 'package:app/model/apis/api_response.dart';
 import 'package:app/model/services/backend_service.dart';
 import 'package:app/model/view_model/account_vm.dart';
 import 'package:app/pages/login_overlay.dart';
+import 'package:app/pages/persons_page.dart';
 import 'package:app/widgets/background.dart';
 import 'package:app/widgets/bottom_navigation.dart';
 import 'package:app/widgets/bottom_navigation_item.dart';
@@ -28,6 +28,12 @@ class _HomePageState extends State<HomePage> {
   void _init() async {
     _setLoading(true);
     _loggedin = await BackendService.isLoggedIn;
+    // if (!_loggedin) {
+    //   await BackendService.logout();
+    //   Navigator.of(context).pushAndRemoveUntil(
+    //       MaterialPageRoute(builder: (builder) => HomePage()),
+    //       (route) => false);
+    // }
     _setLoading(false);
   }
 
@@ -37,6 +43,17 @@ class _HomePageState extends State<HomePage> {
     });
   }
 
+  void _checkResponse(ApiResponse response) async {
+    print('${response.message}');
+    if (response.status == Status.ERROR &&
+        response.message!.contains('unauthorized')) {
+      await BackendService.logout();
+      Navigator.of(context).pushAndRemoveUntil(
+          MaterialPageRoute(builder: (builder) => const HomePage()),
+          (route) => false);
+    }
+  }
+
   bool _loading = true;
   bool _loggedin = false;
   @override
@@ -45,114 +62,143 @@ class _HomePageState extends State<HomePage> {
       child: ChangeNotifierProvider<AccountViewModel>(
         create: (context) => AccountViewModel(),
         child: Consumer<AccountViewModel>(
-          builder: (context, value, child) => Scaffold(
-            appBar: AppBar(
-              automaticallyImplyLeading: false,
-              // flexibleSpace: Image.asset(
-              //   'lib/assets/logo_300x200.png',
-              //   // height: 400,
-              // ),
-            ),
-            drawer: SideDrawer(
-              children: [
-                const Spacer(
-                  flex: 3,
-                ),
-                SideDrawerItem(
-                  onPressed: () {},
-                  icon: Icons.question_answer,
-                  color: Colors.white,
-                  label: 'About',
-                ),
-                SideDrawerItem(
-                  onPressed: () {},
-                  icon: Icons.privacy_tip,
-                  color: Colors.white,
-                  label: 'Datenschutz',
-                ),
-                SideDrawerItem(
-                  onPressed: () {},
-                  icon: Icons.apartment,
-                  color: Colors.white,
-                  label: 'Impressum',
-                ),
-                const Spacer(
-                  flex: 1,
-                ),
-                if (_loggedin || value.response.data != null)
+          builder: (context, value, child) {
+            _checkResponse(value.response);
+            return Scaffold(
+              appBar: AppBar(
+                automaticallyImplyLeading: false,
+                // flexibleSpace: Image.asset(
+                //   'lib/assets/logo_300x200.png',
+                //   // height: 400,
+                // ),
+              ),
+              drawer: SideDrawer(
+                children: [
+                  const Spacer(
+                    flex: 3,
+                  ),
                   SideDrawerItem(
                     onPressed: () {},
-                    icon: Icons.logout,
+                    icon: Icons.question_answer,
                     color: Colors.white,
-                    label: 'Logout',
+                    label: 'About',
                   ),
-              ],
-            ),
-            bottomNavigationBar: BottomNavigation(
-              children: [
-                if (!_loggedin) ...[
-                  BottomNavigationItem(
+                  SideDrawerItem(
                     onPressed: () {},
-                    icon: Icons.person_add_alt,
+                    icon: Icons.privacy_tip,
                     color: Colors.white,
-                    label: 'Registrieren',
+                    label: 'Datenschutz',
                   ),
-                  BottomNavigationItem(
-                    onPressed: () async {
-                      _loggedin = await showLogin(context);
-                    },
-                    icon: Icons.login,
-                    color: Colors.white,
-                    label: 'Login',
-                  ),
-                ] else
-                  BottomNavigationItem(
+                  SideDrawerItem(
                     onPressed: () {},
-                    icon: Icons.person_search,
+                    icon: Icons.apartment,
                     color: Colors.white,
-                    label: 'Personen',
+                    label: 'Impressum',
                   ),
-                BottomNavigationItem(
-                  onPressed: () {},
-                  icon: Icons.dashboard,
-                  color: Colors.white,
-                  label: 'Dashboard',
-                ),
-                ...[]
-              ],
-            ),
-            body: Padding(
-              padding: const EdgeInsets.fromLTRB(16, 40, 16, 16),
-              child: Center(
-                child: _loading
-                    ? const CircularProgressIndicator(
-                        color: Colors.grey,
-                      )
-                    : Column(
-                        children: [
-                          Image.asset(
-                            'lib/assets/logo_300x200.png',
-                          ),
-                          const SizedBox(
-                            height: 40,
-                          ),
-                          Text(
-                            'Digitale Spuren auf Knopfdruck entfernen'
-                                .toUpperCase(),
-                            textAlign: TextAlign.center,
-                            style: const TextStyle(
-                              fontFamily: 'sans-serif',
-                              fontSize: 24,
-                              height: 1.6,
-                              fontWeight: FontWeight.normal,
-                              letterSpacing: 6,
-                            ),
-                          ),
-                        ],
-                      ),
+                  const Spacer(
+                    flex: 1,
+                  ),
+                  if (_loggedin && value.response.data != null)
+                    SideDrawerItem(
+                      onPressed: () async {
+                        setState(() {
+                          _loading = true;
+                        });
+                        await BackendService.logout();
+                        // ignore: use_build_context_synchronously
+                        Navigator.of(context).pushAndRemoveUntil(
+                            MaterialPageRoute(
+                                builder: (builder) => const HomePage()),
+                            (route) => false);
+                        setState(() {
+                          _loggedin = false;
+                          _loading = false;
+                        });
+                      },
+                      icon: Icons.logout,
+                      color: Colors.white,
+                      label: 'Logout',
+                    ),
+                ],
               ),
-            ),
-          ),
+              bottomNavigationBar: BottomNavigation(
+                children: [
+                  if (!_loggedin) ...[
+                    BottomNavigationItem(
+                      onPressed: () async {
+                        final bool res =
+                            await showLogin(context, registration: true);
+                        setState(() {
+                          _loggedin = res;
+                        });
+                      },
+                      icon: Icons.person_add_alt,
+                      color: Colors.white,
+                      label: 'Registrieren',
+                    ),
+                    BottomNavigationItem(
+                      onPressed: () async {
+                        final bool res = await showLogin(context);
+                        setState(() {
+                          _loggedin = res;
+                        });
+                      },
+                      icon: Icons.login,
+                      color: Colors.white,
+                      label: 'Login',
+                    ),
+                  ] else
+                    BottomNavigationItem(
+                      onPressed: () {
+                        Navigator.of(context).push(MaterialPageRoute(
+                            builder: (builder) => const PersonsPage()));
+                      },
+                      icon: Icons.person_search,
+                      color: Colors.white,
+                      label: 'Personen',
+                    ),
+                  BottomNavigationItem(
+                    onPressed: () {},
+                    icon: Icons.dashboard,
+                    color: Colors.white,
+                    label: 'Dashboard',
+                  ),
+                  ...[]
+                ],
+              ),
+              body: Padding(
+                padding: const EdgeInsets.fromLTRB(16, 40, 16, 16),
+                child: Center(
+                  child: _loading
+                      ? const CircularProgressIndicator(
+                          color: Colors.grey,
+                        )
+                      : Column(
+                          children: [
+                            Image.asset(
+                              'lib/assets/logo_300x200.png',
+                            ),
+                            const SizedBox(
+                              height: 40,
+                            ),
+                            Text(
+                              'Digitale Spuren auf Knopfdruck entfernen'
+                                  .toUpperCase(),
+                              textAlign: TextAlign.center,
+                              style: const TextStyle(
+                                fontFamily: 'sans-serif',
+                                fontSize: 24,
+                                height: 1.6,
+                                fontWeight: FontWeight.normal,
+                                letterSpacing: 6,
+                              ),
+                            ),
+                          ],
+                        ),
+                ),
+              ),
+            );
+          },
         ),
       ),
     );
diff --git a/frontend/app/lib/pages/login_overlay.dart b/frontend/app/lib/pages/login_overlay.dart
index 6d59622..927dc46 100644
--- a/frontend/app/lib/pages/login_overlay.dart
+++ b/frontend/app/lib/pages/login_overlay.dart
@@ -1,8 +1,10 @@
 import 'package:app/model/services/backend_service.dart';
 import 'package:app/widgets/background.dart';
 import 'package:flutter/material.dart';
+import 'package:app/util/validation.dart';
 
-Future<bool> showLogin(BuildContext context) async {
+Future<bool> showLogin(BuildContext context,
+    {bool registration = false}) async {
   final formKey = GlobalKey<FormState>();
   final mailController = TextEditingController();
   final passwordController = TextEditingController();
@@ -26,6 +28,23 @@ Future<bool> showLogin(BuildContext context) async {
     }
   }
 
+  void register() {
+    if (formKey.currentState!.validate()) {
+      submitted = true;
+      BackendService.createAccount(
+        email: mailController.text,
+        password: passwordController.text,
+      ).then(
+        (r) {
+          if (r) {
+            loggedin = r;
+            Navigator.pop(context, true);
+          }
+        },
+      );
+    }
+  }
+
   await showModalBottomSheet(
       useSafeArea: true,
       isScrollControlled: true,
@@ -48,9 +67,9 @@ Future<bool> showLogin(BuildContext context) async {
               const SizedBox(
                 height: 30,
               ),
-              const Text(
-                'Login',
-                style: TextStyle(
+              Text(
+                registration ? 'Registrieren' : 'Login',
+                style: const TextStyle(
                   fontFamily: 'sans-serif',
                   fontSize: 24,
                   height: 1.6,
@@ -68,6 +87,12 @@ Future<bool> showLogin(BuildContext context) async {
                       height: 40,
                     ),
                     TextFormField(
+                      autofocus: true,
+                      // inputFormatters: [
+                      //   FilteringTextInputFormatter.allow(
+                      //     emailRegExp,
+                      //   ),
+                      // ],
                       controller: mailController,
                       decoration: const InputDecoration(
                         fillColor: Color.fromARGB(30, 255, 255, 255),
@@ -79,7 +104,7 @@ Future<bool> showLogin(BuildContext context) async {
                       ),
                       keyboardType: TextInputType.emailAddress,
                       validator: (value) {
-                        if (value == null || value.isEmpty) {
+                        if (value == null || !value.isValidEmail) {
                           return 'Bitte eine gültige E-Mail Adresse eingeben';
                         }
                         return null;
@@ -89,6 +114,11 @@ Future<bool> showLogin(BuildContext context) async {
                       style: const TextStyle(
                         color: Colors.white,
                       ),
+                      // inputFormatters: [
+                      //   FilteringTextInputFormatter.allow(
+                      //     passwordRegExp,
+                      //   ),
+                      // ],
                       controller: passwordController,
                       decoration: const InputDecoration(
                         fillColor: Color.fromARGB(30, 255, 255, 255),
@@ -101,7 +131,7 @@ Future<bool> showLogin(BuildContext context) async {
                       keyboardType: TextInputType.visiblePassword,
                       obscureText: true,
                       validator: (value) {
-                        if (value == null || value.isEmpty) {
+                        if (value == null || !value.isValidPassword) {
                           return 'Bitte geben Sie Ihr Passwort ein';
                         }
                         return null;
@@ -122,7 +152,11 @@ Future<bool> showLogin(BuildContext context) async {
                           child: const Icon(Icons.arrow_back),
                         ),
                         ElevatedButton(
-                          onPressed: !submitted ? login : null,
+                          onPressed: !submitted
+                              ? !registration
+                                  ? login
+                                  : register
+                              : null,
                           child: const Icon(Icons.login),
                         ),
                       ],
diff --git a/frontend/app/lib/pages/persons_page.dart b/frontend/app/lib/pages/persons_page.dart
new file mode 100644
index 0000000..746dfad
--- /dev/null
+++ b/frontend/app/lib/pages/persons_page.dart
@@ -0,0 +1,174 @@
+import 'package:app/model/apis/api_response.dart';
+import 'package:app/model/services/backend_service.dart';
+import 'package:app/model/view_model/persons_vm.dart';
+import 'package:app/pages/home_page.dart';
+import 'package:app/pb/person.pb.dart';
+import 'package:app/widgets/background.dart';
+import 'package:app/widgets/bottom_navigation.dart';
+import 'package:app/widgets/bottom_navigation_item.dart';
+import 'package:app/widgets/side_drawer.dart';
+import 'package:app/widgets/side_drawer_item.dart';
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+
+class PersonsPage extends StatefulWidget {
+  const PersonsPage({super.key});
+
+  @override
+  State<PersonsPage> createState() => _PersonsPageState();
+}
+
+class _PersonsPageState extends State<PersonsPage> {
+  @override
+  void initState() {
+    super.initState();
+    _init();
+  }
+
+  void _init() async {
+    _setLoading(true);
+    _loggedin = await BackendService.isLoggedIn;
+    _setLoading(false);
+  }
+
+  void _setLoading(bool loading) {
+    setState(() {
+      _loading = loading;
+    });
+  }
+
+  void _checkResponse(ApiResponse response) {
+    if (response.status == Status.ERROR &&
+        response.message!.contains('unauthenticated')) {
+      BackendService.logout();
+      Navigator.of(context).pushAndRemoveUntil(
+          MaterialPageRoute(builder: (builder) => const HomePage()),
+          (route) => false);
+    }
+  }
+
+  bool _loading = true;
+  bool _loggedin = false;
+
+  List<Widget> _personsList(List<Person> persons) {
+    final List<Widget> list = [];
+    for (var p in persons) {
+      list.add(Card(
+        color: Colors.black,
+        child: Text(
+          '${p.firstname} ${p.lastname}',
+          style: const TextStyle(color: Colors.white),
+        ),
+      ));
+    }
+    return list;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Background(
+      child: ChangeNotifierProvider<PersonsViewModel>(
+        create: (context) => PersonsViewModel(),
+        child: Consumer<PersonsViewModel>(
+          builder: (context, value, child) {
+            _checkResponse(value.response);
+            return Scaffold(
+              floatingActionButtonLocation:
+                  FloatingActionButtonLocation.centerFloat,
+              floatingActionButton: FloatingActionButton(
+                onPressed: () {},
+                child: const Icon(Icons.add),
+              ),
+              appBar: AppBar(
+                automaticallyImplyLeading: false,
+              ),
+              drawer: SideDrawer(
+                children: [
+                  const Spacer(
+                    flex: 3,
+                  ),
+                  SideDrawerItem(
+                    onPressed: () {},
+                    icon: Icons.question_answer,
+                    color: Colors.white,
+                    label: 'About',
+                  ),
+                  SideDrawerItem(
+                    onPressed: () {},
+                    icon: Icons.privacy_tip,
+                    color: Colors.white,
+                    label: 'Datenschutz',
+                  ),
+                  SideDrawerItem(
+                    onPressed: () {},
+                    icon: Icons.apartment,
+                    color: Colors.white,
+                    label: 'Impressum',
+                  ),
+                  const Spacer(
+                    flex: 1,
+                  ),
+                  if (_loggedin || value.response.data != null)
+                    SideDrawerItem(
+                      onPressed: () async {
+                        setState(() {
+                          _loading = true;
+                        });
+                        await BackendService.logout();
+                        // ignore: use_build_context_synchronously
+                        Navigator.of(context).pushAndRemoveUntil(
+                            MaterialPageRoute(
+                                builder: (builder) => const HomePage()),
+                            (route) => false);
+                        setState(() {
+                          _loggedin = false;
+                          _loading = false;
+                        });
+                      },
+                      icon: Icons.logout,
+                      color: Colors.white,
+                      label: 'Logout',
+                    ),
+                ],
+              ),
+              bottomNavigationBar: BottomNavigation(
+                children: [
+                  BottomNavigationItem(
+                    onPressed: () {},
+                    icon: Icons.dashboard,
+                    color: Colors.white,
+                    label: 'Dashboard',
+                  ),
+                  BottomNavigationItem(
+                    onPressed: () {
+                      Navigator.of(context).pop();
+                    },
+                    icon: Icons.home,
+                    color: Colors.white,
+                    label: 'Home',
+                  ),
+                ],
+              ),
+              body: Padding(
+                padding: const EdgeInsets.all(16),
+                child: Center(
+                  child: _loading
+                      ? const CircularProgressIndicator(
+                          color: Colors.grey,
+                        )
+                      : value.response.status == Status.COMPLETED
+                          ? value.response.data.length > 0
+                              ? ListView(
+                                  children: _personsList(
+                                      (value.response.data as List<Person>)))
+                              : const Text('Noch keine Personen angelegt')
+                          : const Text('Lade Daten...'),
+                ),
+              ),
+            );
+          },
+        ),
+      ),
+    );
+  }
+}
diff --git a/frontend/app/lib/util/validation.dart b/frontend/app/lib/util/validation.dart
new file mode 100644
index 0000000..a7aa9e5
--- /dev/null
+++ b/frontend/app/lib/util/validation.dart
@@ -0,0 +1,27 @@
+final emailRegExp = RegExp(r"^[a-zA-Z0-9.]+@[a-zA-Z0-9]+\.[a-zA-Z]+");
+final nameRegExp =
+    RegExp(r"^\s*([A-Za-z]{1,}([\.,] |[-']| ))+[A-Za-z]+\.?\s*$");
+final phoneRegExp = RegExp(r"^\+?0[0-9]{10}$");
+final passwordRegExp = RegExp(r'^.+$');
+
+extension valString on String {
+  bool get isValidEmail {
+    return emailRegExp.hasMatch(this);
+  }
+
+  bool get isValidName {
+    return nameRegExp.hasMatch(this);
+  }
+
+  bool get isValidPassword {
+    return passwordRegExp.hasMatch(this);
+  }
+
+  bool get isNotEmpty {
+    return this != trim();
+  }
+
+  bool get isValidPhone {
+    return phoneRegExp.hasMatch(this);
+  }
+}

From c4da7bea27db9e0727255a77eb771d225076559f Mon Sep 17 00:00:00 2001
From: itsscb <dev@itsscb.de>
Date: Tue, 7 Nov 2023 00:22:11 +0100
Subject: [PATCH 24/24] ft/adds toasts to api calls

---
 frontend/app/lib/data/database.dart           |   3 +-
 frontend/app/lib/main.dart                    |   4 +-
 frontend/app/lib/model/apis/api_response.dart |   2 +-
 .../lib/model/services/backend_service.dart   |  53 ++-
 .../app/lib/model/view_model/account_vm.dart  |  42 +--
 .../app/lib/model/view_model/base_vm.dart     | 254 ++++++++++++++
 .../app/lib/model/view_model/persons_vm.dart  |  38 +-
 frontend/app/lib/pages/home_page.dart         | 326 +++++++++---------
 frontend/app/lib/pages/login_overlay.dart     | 298 +++++++++-------
 frontend/app/lib/pages/persons_page.dart      | 196 ++++++-----
 frontend/app/lib/util/colors.dart             |  11 +
 .../app/lib/widgets/bottom_navigation.dart    |   1 +
 .../lib/widgets/bottom_navigation_item.dart   |   1 +
 frontend/app/lib/widgets/drawer.dart          |   5 +-
 .../app/lib/widgets/side_drawer_item.dart     |   2 +-
 15 files changed, 818 insertions(+), 418 deletions(-)
 create mode 100644 frontend/app/lib/model/view_model/base_vm.dart
 create mode 100644 frontend/app/lib/util/colors.dart

diff --git a/frontend/app/lib/data/database.dart b/frontend/app/lib/data/database.dart
index 1ae9a7f..42b37c8 100644
--- a/frontend/app/lib/data/database.dart
+++ b/frontend/app/lib/data/database.dart
@@ -1,5 +1,4 @@
 import 'dart:async';
-import 'package:app/pb/session.pbjson.dart';
 import 'package:fixnum/fixnum.dart';
 
 import 'package:app/pb/google/protobuf/timestamp.pb.dart';
@@ -167,7 +166,7 @@ class Session {
     final db = await database;
 
     final List<Map<String, Object?>> maps = await db.query('sessions');
-    print(maps);
+    // print(maps);
     final List<Session> sessions = List.generate(
       maps.length,
       (i) {
diff --git a/frontend/app/lib/main.dart b/frontend/app/lib/main.dart
index 14f789a..6b36af7 100644
--- a/frontend/app/lib/main.dart
+++ b/frontend/app/lib/main.dart
@@ -41,7 +41,9 @@ void main() async {
             backgroundColor: Colors.black,
             foregroundColor: Colors.white,
           )),
-      home: const HomePage(),
+      home: HomePage(
+        loggedOut: false,
+      ),
     ),
   );
 }
diff --git a/frontend/app/lib/model/apis/api_response.dart b/frontend/app/lib/model/apis/api_response.dart
index 764c500..6300f64 100644
--- a/frontend/app/lib/model/apis/api_response.dart
+++ b/frontend/app/lib/model/apis/api_response.dart
@@ -5,7 +5,7 @@ class ApiResponse<T> {
 
   ApiResponse.initial(this.message) : status = Status.INITIAL;
   ApiResponse.loading(this.message) : status = Status.LOADING;
-  ApiResponse.completed(this.data, this.message) : status = Status.COMPLETED;
+  ApiResponse.completed(this.data) : status = Status.COMPLETED;
   ApiResponse.error(this.message) : status = Status.ERROR;
 
   @override
diff --git a/frontend/app/lib/model/services/backend_service.dart b/frontend/app/lib/model/services/backend_service.dart
index 669bc3e..af38df8 100644
--- a/frontend/app/lib/model/services/backend_service.dart
+++ b/frontend/app/lib/model/services/backend_service.dart
@@ -3,9 +3,11 @@ import 'dart:io';
 import 'package:app/model/apis/app_exception.dart';
 import 'package:app/pb/account.pb.dart';
 import 'package:app/pb/account_info.pb.dart';
+import 'package:app/pb/google/protobuf/timestamp.pb.dart';
 import 'package:app/pb/person.pb.dart';
 import 'package:app/data/database.dart';
 import 'package:app/pb/rpc_create_account.pb.dart';
+import 'package:app/pb/rpc_create_person.pb.dart';
 import 'package:app/pb/rpc_get_account.pb.dart';
 import 'package:app/pb/rpc_get_account_info.pb.dart';
 import 'package:app/pb/rpc_get_person.pb.dart';
@@ -15,7 +17,6 @@ import 'package:app/pb/rpc_refresh_token.pb.dart';
 import 'package:app/pb/service_df.pbgrpc.dart';
 import 'package:fixnum/fixnum.dart';
 import 'package:grpc/grpc.dart';
-import 'package:sqflite/sqflite.dart';
 
 class BackendService {
   BackendService() {
@@ -138,17 +139,16 @@ class BackendService {
     }
     try {
       final GetAccountResponse response = await _client.getAccount(
-          GetAccountRequest(id: session!.accountId),
+          GetAccountRequest(id: session.accountId),
           options: CallOptions(
               metadata: {'Authorization': 'Bearer ${session.accessToken}'}));
       return response.account;
     } on SocketException {
       throw FetchDataException('Keine Internet Verbindung');
     } on GrpcError catch (err) {
-      // if (err.code == 16) {
-      //   await refreshToken(session);
-      //   return getAccount();
-      // }
+      if (err.code == 16) {
+        throw UnauthorizedException(err.message);
+      }
       throw FetchDataException(err.message);
     } catch (err) {
       throw InternalException(err.toString());
@@ -207,6 +207,47 @@ class BackendService {
     }
   }
 
+  Future<Person> createPerson(
+      {required String firstname,
+      required String lastname,
+      required String street,
+      required String zip,
+      required String city,
+      required String country,
+      required DateTime birthday}) async {
+    Session session = await Session.session;
+    if (session.accessTokenExpiresAt == null) {
+      throw UnauthorizedException('Keine Siztung gefunden');
+    }
+    if (session.accessTokenExpiresAt!.toDateTime().isBefore(DateTime.now())) {
+      session = await refreshToken(session);
+      if (session.accessTokenExpiresAt == null) {
+        throw UnauthorizedException('Sitzung ist abgelaufen');
+      }
+    }
+    try {
+      final CreatePersonResponse response = await _client.createPerson(
+          CreatePersonRequest(
+            accountId: session.accountId,
+            lastname: lastname,
+            firstname: firstname,
+            street: street,
+            zip: zip,
+            country: country,
+            birthday: Timestamp.fromDateTime(birthday),
+          ),
+          options: CallOptions(
+              metadata: {'Authorization': 'Bearer ${session.accessToken}'}));
+      return response.person;
+    } on SocketException {
+      throw FetchDataException('Keine Internet Verbindung');
+    } on GrpcError catch (err) {
+      throw FetchDataException(err.message);
+    } catch (err) {
+      throw InternalException(err.toString());
+    }
+  }
+
   Future<List<Person>> listPersons() async {
     Session session = await Session.session;
     if (session.accessTokenExpiresAt == null) {
diff --git a/frontend/app/lib/model/view_model/account_vm.dart b/frontend/app/lib/model/view_model/account_vm.dart
index 13356fa..fb3a998 100644
--- a/frontend/app/lib/model/view_model/account_vm.dart
+++ b/frontend/app/lib/model/view_model/account_vm.dart
@@ -1,9 +1,9 @@
 import 'package:app/model/apis/api_response.dart';
 import 'package:app/model/services/backend_service.dart';
+import 'package:app/model/view_model/base_vm.dart';
 import 'package:app/pb/account.pb.dart';
-import 'package:flutter/material.dart';
 
-class AccountViewModel with ChangeNotifier {
+class AccountViewModel extends BaseViewModel {
   AccountViewModel() {
     _init();
   }
@@ -21,36 +21,12 @@ class AccountViewModel with ChangeNotifier {
   }
 
   void _init() async {
-    _apiResponse = ApiResponse.loading('Bereite alles vor');
-    try {
-      _apiResponse = ApiResponse.completed(await _service.getAccount(), 'done');
-    } catch (e) {
-      _apiResponse = ApiResponse.error(e.toString());
-    }
-    notifyListeners();
-  }
-
-  Future<void> fetchAccount() async {
-    _apiResponse = ApiResponse.loading('Hole Account');
-    notifyListeners();
-    try {
-      _apiResponse = ApiResponse.completed(await _service.getAccount(), 'done');
-    } catch (e) {
-      _apiResponse = ApiResponse.error(e.toString());
-    }
-    notifyListeners();
-  }
-
-  Future<void> logout() async {
-    _apiResponse = ApiResponse.loading('Logge aus');
-    notifyListeners();
-    try {
-      await BackendService.logout();
-      _apiResponse = ApiResponse.completed(null, 'Erfolgreich ausgeloggt');
-    } catch (e) {
-      _apiResponse = ApiResponse.error(e.toString());
-    }
-    print(_apiResponse.message);
-    notifyListeners();
+    super.init();
+    // try {
+    //   _apiResponse = ApiResponse.completed(await _service.getAccount());
+    // } catch (e) {
+    //   _apiResponse = ApiResponse.error(e.toString());
+    // }
+    // notifyListeners();
   }
 }
diff --git a/frontend/app/lib/model/view_model/base_vm.dart b/frontend/app/lib/model/view_model/base_vm.dart
new file mode 100644
index 0000000..7745a8e
--- /dev/null
+++ b/frontend/app/lib/model/view_model/base_vm.dart
@@ -0,0 +1,254 @@
+import 'package:app/model/apis/api_response.dart';
+import 'package:app/model/services/backend_service.dart';
+import 'package:app/pages/home_page.dart';
+import 'package:app/util/colors.dart';
+import 'package:flutter/material.dart';
+
+class BaseViewModel with ChangeNotifier {
+  BaseViewModel() {
+    init();
+  }
+  ApiResponse _apiResponse = ApiResponse.initial('Keine Daten');
+
+  final BackendService _service = BackendService();
+
+  ApiResponse get response {
+    return _apiResponse;
+  }
+
+  void init() async {
+    // if (await BackendService.isLoggedIn) {
+    try {
+      _apiResponse = ApiResponse.completed(await _service.getAccount());
+    } catch (e) {
+      _apiResponse = ApiResponse.error(e.toString());
+    }
+    notifyListeners();
+    // }
+  }
+
+  Future<bool> isLoggedIn(BuildContext context) async {
+    final messenger = ScaffoldMessenger.of(context);
+    final navigator = Navigator.of(context);
+    bool loggedIn = false;
+    try {
+      loggedIn = await BackendService.isLoggedIn;
+    } catch (err) {
+      if (err.toString().contains('session is blocked')) {
+        _apiResponse = ApiResponse.error('Sitzung ist abgelaufen');
+        navigator.pushAndRemoveUntil(
+            MaterialPageRoute(
+                builder: (builder) => HomePage(
+                      loggedOut: true,
+                    )),
+            (route) => false);
+        messenger.showSnackBar(SnackBar(
+          backgroundColor: CustomColors.error,
+          content: const Text(
+            'Sitzung ist abgelaufen',
+            style: TextStyle(color: Colors.white),
+          ),
+          // action: SnackBarAction(
+          //   label: 'Details',
+          //   onPressed: () {
+          //     if (context.mounted) {
+          //       showDialog(
+          //           context: context,
+          //           builder: (context) => AlertDialog(
+          //                 backgroundColor: Colors.black,
+          //                 icon: Icon(
+          //                   Icons.error,
+          //                   color: CustomColors.error,
+          //                 ),
+          //                 content: Text(
+          //                   err.toString(),
+          //                   textAlign: TextAlign.center,
+          //                 ),
+          //               ));
+          //     }
+          //   },
+          // ),
+        ));
+      }
+    }
+    return loggedIn;
+  }
+
+  Future<void> getAccount(BuildContext context) async {
+    _apiResponse = ApiResponse.loading('Lade Daten');
+    notifyListeners();
+    final messenger = ScaffoldMessenger.of(context);
+    try {
+      _apiResponse = ApiResponse.completed(await _service.getAccount());
+    } catch (e) {
+      if (e.toString().contains('session is blocked')) {
+        _apiResponse = ApiResponse.error('Sitzung ist abgelaufen');
+        messenger.showSnackBar(SnackBar(
+          backgroundColor: CustomColors.error,
+          content: const Text(
+            'Sitzung ist abgelaufen',
+            style: TextStyle(color: Colors.white),
+          ),
+          action: SnackBarAction(
+            label: 'Details',
+            onPressed: () {
+              showDialog(
+                  context: context,
+                  builder: (context) => AlertDialog(
+                        backgroundColor: Colors.black,
+                        icon: Icon(
+                          Icons.error,
+                          color: CustomColors.error,
+                        ),
+                        content: Text(
+                          e.toString(),
+                          textAlign: TextAlign.center,
+                        ),
+                      ));
+            },
+          ),
+        ));
+      }
+      messenger.showSnackBar(SnackBar(
+        backgroundColor: CustomColors.error,
+        content: const Text(
+          'Sitzung ist abgelaufen',
+          style: TextStyle(color: Colors.white),
+        ),
+        action: SnackBarAction(
+          label: 'Details',
+          onPressed: () {
+            showDialog(
+                context: context,
+                builder: (context) => AlertDialog(
+                      backgroundColor: Colors.black,
+                      icon: Icon(
+                        Icons.error,
+                        color: CustomColors.error,
+                      ),
+                      content: Text(
+                        e.toString(),
+                        textAlign: TextAlign.center,
+                      ),
+                    ));
+          },
+        ),
+      ));
+      _apiResponse = ApiResponse.error(e.toString());
+    }
+    notifyListeners();
+  }
+
+  Future<void> logout() async {
+    _apiResponse = ApiResponse.loading('Logge aus');
+    notifyListeners();
+    try {
+      await BackendService.logout();
+      _apiResponse = ApiResponse.completed(true);
+    } catch (e) {
+      _apiResponse = ApiResponse.error(e.toString());
+    }
+    print(_apiResponse.message);
+    notifyListeners();
+  }
+
+  Future<bool> login(BuildContext context,
+      {required String email, required String password}) async {
+    bool resp = false;
+    _apiResponse = ApiResponse.loading('Logge ein');
+    notifyListeners();
+    final messenger = ScaffoldMessenger.of(context);
+    try {
+      resp = await BackendService.login(email: email, password: password);
+      _apiResponse = ApiResponse.completed(resp);
+      messenger.showSnackBar(SnackBar(
+        backgroundColor: CustomColors.success,
+        content: const Text(
+          'Erfolgreich eingeloggt',
+          style: TextStyle(color: Colors.white),
+        ),
+      ));
+    } catch (e) {
+      messenger.showSnackBar(SnackBar(
+        backgroundColor: CustomColors.error,
+        content: const Text(
+          'Login fehlgeschlagen',
+          style: TextStyle(color: Colors.white),
+        ),
+        action: SnackBarAction(
+          label: 'Details',
+          onPressed: () {
+            showDialog(
+                context: context,
+                builder: (context) => AlertDialog(
+                      backgroundColor: Colors.black,
+                      icon: Icon(
+                        Icons.error,
+                        color: CustomColors.error,
+                      ),
+                      content: Text(
+                        e.toString(),
+                        textAlign: TextAlign.center,
+                      ),
+                    ));
+          },
+        ),
+      ));
+      _apiResponse = ApiResponse.error(e.toString());
+    }
+    print(_apiResponse.message);
+    notifyListeners();
+    return resp;
+  }
+
+  Future<bool> createAccount(BuildContext context,
+      {required String email, required String password}) async {
+    bool resp = false;
+    final messenger = ScaffoldMessenger.of(context);
+
+    _apiResponse = ApiResponse.loading('Logge ein');
+    notifyListeners();
+    try {
+      resp =
+          await BackendService.createAccount(email: email, password: password);
+      messenger.showSnackBar(SnackBar(
+        backgroundColor: CustomColors.success,
+        content: const Text(
+          'Account angelegt',
+          style: TextStyle(color: Colors.white),
+        ),
+      ));
+      _apiResponse = ApiResponse.completed(resp);
+    } catch (e) {
+      messenger.showSnackBar(SnackBar(
+        backgroundColor: CustomColors.error,
+        content: const Text(
+          'Account anlegen fehlgeschlagen',
+          style: TextStyle(color: Colors.white),
+        ),
+        action: SnackBarAction(
+          label: 'Details',
+          onPressed: () {
+            showDialog(
+                context: context,
+                builder: (context) => AlertDialog(
+                      backgroundColor: Colors.black,
+                      icon: Icon(
+                        Icons.error,
+                        color: CustomColors.error,
+                      ),
+                      content: Text(
+                        e.toString(),
+                        textAlign: TextAlign.center,
+                      ),
+                    ));
+          },
+        ),
+      ));
+      _apiResponse = ApiResponse.error(e.toString());
+    }
+    print(_apiResponse.message);
+    notifyListeners();
+    return resp;
+  }
+}
diff --git a/frontend/app/lib/model/view_model/persons_vm.dart b/frontend/app/lib/model/view_model/persons_vm.dart
index 40e4606..a8ed578 100644
--- a/frontend/app/lib/model/view_model/persons_vm.dart
+++ b/frontend/app/lib/model/view_model/persons_vm.dart
@@ -1,6 +1,5 @@
 import 'package:app/model/apis/api_response.dart';
 import 'package:app/model/services/backend_service.dart';
-import 'package:app/pb/account.pb.dart';
 import 'package:app/pb/person.pb.dart';
 import 'package:flutter/material.dart';
 
@@ -16,14 +15,43 @@ class PersonsViewModel with ChangeNotifier {
     return _apiResponse;
   }
 
-  void listPersons() async {
-    _apiResponse = ApiResponse.loading('Bereite alles vor');
+  Future<List<Person>> listPersons() async {
+    List<Person> persons = [];
+    _apiResponse = ApiResponse.loading('Lade Daten');
     try {
-      _apiResponse =
-          ApiResponse.completed(await _service.listPersons(), 'done');
+      persons = await _service.listPersons();
+      _apiResponse = ApiResponse.completed(persons);
     } catch (e) {
       _apiResponse = ApiResponse.error(e.toString());
     }
     notifyListeners();
+    return persons;
+  }
+
+  Future<Person> createPerson(BuildContext context,
+      {required String firstname,
+      required String lastname,
+      required String street,
+      required String zip,
+      required String city,
+      required String country,
+      required DateTime birthday}) async {
+    Person person = Person();
+    _apiResponse = ApiResponse.loading('Erstelle Person');
+    try {
+      person = await _service.createPerson(
+          firstname: firstname,
+          lastname: lastname,
+          street: street,
+          zip: zip,
+          city: city,
+          country: country,
+          birthday: birthday);
+      _apiResponse = ApiResponse.completed(person);
+    } catch (err) {
+      _apiResponse = ApiResponse.error(err.toString());
+    }
+    notifyListeners();
+    return person;
   }
 }
diff --git a/frontend/app/lib/pages/home_page.dart b/frontend/app/lib/pages/home_page.dart
index c2eb137..7b62f12 100644
--- a/frontend/app/lib/pages/home_page.dart
+++ b/frontend/app/lib/pages/home_page.dart
@@ -1,4 +1,3 @@
-import 'package:app/model/apis/api_response.dart';
 import 'package:app/model/services/backend_service.dart';
 import 'package:app/model/view_model/account_vm.dart';
 import 'package:app/pages/login_overlay.dart';
@@ -11,8 +10,11 @@ import 'package:app/widgets/side_drawer_item.dart';
 import 'package:flutter/material.dart';
 import 'package:provider/provider.dart';
 
+// ignore: must_be_immutable
 class HomePage extends StatefulWidget {
-  const HomePage({super.key});
+  HomePage({super.key, required this.loggedOut});
+
+  bool loggedOut;
 
   @override
   State<HomePage> createState() => _HomePageState();
@@ -25,182 +27,192 @@ class _HomePageState extends State<HomePage> {
     _init();
   }
 
+  AccountViewModel vm = AccountViewModel();
   void _init() async {
-    _setLoading(true);
-    _loggedin = await BackendService.isLoggedIn;
+    // _setLoading(true);
+    // _setLoading(widget.loggedOut);
+    // _loading = widget.loggedOut;
+    // _loggedin = await BackendService.isLoggedIn;
     // if (!_loggedin) {
     //   await BackendService.logout();
-    //   Navigator.of(context).pushAndRemoveUntil(
-    //       MaterialPageRoute(builder: (builder) => HomePage()),
+    //   final navigator = Navigator.of(context);
+    //   navigator.pushAndRemoveUntil(
+    //       MaterialPageRoute(
+    //           builder: (builder) => HomePage(
+    //                 loggedOut: true,
+    //               )),
     //       (route) => false);
     // }
     _setLoading(false);
   }
 
+  _isLoggedIn(BuildContext context) async {
+    bool logged = await vm.isLoggedIn(context);
+    _loggedin = logged;
+  }
+
   void _setLoading(bool loading) {
     setState(() {
       _loading = loading;
     });
   }
 
-  void _checkResponse(ApiResponse response) async {
-    print('${response.message}');
-    if (response.status == Status.ERROR &&
-        response.message!.contains('unauthorized')) {
-      await BackendService.logout();
-      Navigator.of(context).pushAndRemoveUntil(
-          MaterialPageRoute(builder: (builder) => const HomePage()),
-          (route) => false);
-    }
-  }
-
   bool _loading = true;
   bool _loggedin = false;
   @override
   Widget build(BuildContext context) {
     return Background(
-      child: ChangeNotifierProvider<AccountViewModel>(
-        create: (context) => AccountViewModel(),
-        child: Consumer<AccountViewModel>(
-          builder: (context, value, child) {
-            _checkResponse(value.response);
-            return Scaffold(
-              appBar: AppBar(
-                automaticallyImplyLeading: false,
-                // flexibleSpace: Image.asset(
-                //   'lib/assets/logo_300x200.png',
-                //   // height: 400,
-                // ),
-              ),
-              drawer: SideDrawer(
-                children: [
-                  const Spacer(
-                    flex: 3,
-                  ),
-                  SideDrawerItem(
-                    onPressed: () {},
-                    icon: Icons.question_answer,
-                    color: Colors.white,
-                    label: 'About',
-                  ),
-                  SideDrawerItem(
-                    onPressed: () {},
-                    icon: Icons.privacy_tip,
-                    color: Colors.white,
-                    label: 'Datenschutz',
-                  ),
-                  SideDrawerItem(
-                    onPressed: () {},
-                    icon: Icons.apartment,
-                    color: Colors.white,
-                    label: 'Impressum',
-                  ),
-                  const Spacer(
-                    flex: 1,
-                  ),
-                  if (_loggedin && value.response.data != null)
-                    SideDrawerItem(
-                      onPressed: () async {
-                        setState(() {
-                          _loading = true;
-                        });
-                        await BackendService.logout();
-                        // ignore: use_build_context_synchronously
-                        Navigator.of(context).pushAndRemoveUntil(
-                            MaterialPageRoute(
-                                builder: (builder) => const HomePage()),
-                            (route) => false);
-                        setState(() {
-                          _loggedin = false;
-                          _loading = false;
-                        });
-                      },
-                      icon: Icons.logout,
-                      color: Colors.white,
-                      label: 'Logout',
-                    ),
-                ],
-              ),
-              bottomNavigationBar: BottomNavigation(
-                children: [
-                  if (!_loggedin) ...[
-                    BottomNavigationItem(
-                      onPressed: () async {
-                        final bool res =
-                            await showLogin(context, registration: true);
-                        setState(() {
-                          _loggedin = res;
-                        });
-                      },
-                      icon: Icons.person_add_alt,
-                      color: Colors.white,
-                      label: 'Registrieren',
-                    ),
-                    BottomNavigationItem(
-                      onPressed: () async {
-                        final bool res = await showLogin(context);
-                        setState(() {
-                          _loggedin = res;
-                        });
-                      },
-                      icon: Icons.login,
-                      color: Colors.white,
-                      label: 'Login',
-                    ),
-                  ] else
-                    BottomNavigationItem(
-                      onPressed: () {
-                        Navigator.of(context).push(MaterialPageRoute(
-                            builder: (builder) => const PersonsPage()));
-                      },
-                      icon: Icons.person_search,
-                      color: Colors.white,
-                      label: 'Personen',
-                    ),
-                  BottomNavigationItem(
-                    onPressed: () {},
-                    icon: Icons.dashboard,
-                    color: Colors.white,
-                    label: 'Dashboard',
-                  ),
-                  ...[]
-                ],
-              ),
-              body: Padding(
-                padding: const EdgeInsets.fromLTRB(16, 40, 16, 16),
-                child: Center(
-                  child: _loading
-                      ? const CircularProgressIndicator(
-                          color: Colors.grey,
-                        )
-                      : Column(
-                          children: [
-                            Image.asset(
-                              'lib/assets/logo_300x200.png',
+        child: Scaffold(
+      appBar: AppBar(
+        automaticallyImplyLeading: false,
+        // flexibleSpace: Image.asset(
+        //   'lib/assets/logo_300x200.png',
+        //   // height: 400,
+        // ),
+      ),
+      drawer: SideDrawer(
+        children: [
+          const Spacer(
+            flex: 3,
+          ),
+          SideDrawerItem(
+            onPressed: () {},
+            icon: Icons.question_answer,
+            color: Colors.white,
+            label: 'About',
+          ),
+          SideDrawerItem(
+            onPressed: () {},
+            icon: Icons.privacy_tip,
+            color: Colors.white,
+            label: 'Datenschutz',
+          ),
+          SideDrawerItem(
+            onPressed: () {},
+            icon: Icons.apartment,
+            color: Colors.white,
+            label: 'Impressum',
+          ),
+          const Spacer(
+            flex: 1,
+          ),
+          if (_loggedin)
+            SideDrawerItem(
+              onPressed: () async {
+                setState(() {
+                  _loading = true;
+                });
+                await BackendService.logout();
+                // ignore: use_build_context_synchronously
+                Navigator.of(context).pushAndRemoveUntil(
+                    MaterialPageRoute(
+                        builder: (builder) => HomePage(
+                              loggedOut: true,
+                            )),
+                    (route) => false);
+                setState(() {
+                  _loggedin = false;
+                  _loading = false;
+                });
+              },
+              icon: Icons.logout,
+              color: Colors.white,
+              label: 'Logout',
+            ),
+        ],
+      ),
+      bottomNavigationBar: BottomNavigation(
+        children: [
+          if (!_loggedin) ...[
+            BottomNavigationItem(
+              onPressed: () async {
+                final bool res = await showLogin(context, registration: true);
+                setState(() {
+                  _loggedin = res;
+                });
+              },
+              icon: Icons.person_add_alt,
+              color: Colors.white,
+              label: 'Registrieren',
+            ),
+            BottomNavigationItem(
+              onPressed: () async {
+                await showLogin(context);
+                setState(() {
+                  vm.isLoggedIn(context);
+                });
+              },
+              icon: Icons.login,
+              color: Colors.white,
+              label: 'Login',
+            ),
+          ] else
+            BottomNavigationItem(
+              onPressed: () async {
+                final navigator = Navigator.of(context);
+                if (await vm.isLoggedIn(context)) {
+                  navigator.push(MaterialPageRoute(
+                      builder: (builder) => const PersonsPage()));
+                } else {
+                  navigator.pushAndRemoveUntil(
+                      MaterialPageRoute(
+                          builder: (builder) => const PersonsPage()),
+                      (route) => false);
+                }
+              },
+              icon: Icons.person_search,
+              color: Colors.white,
+              label: 'Personen',
+            ),
+          BottomNavigationItem(
+            onPressed: () {},
+            icon: Icons.dashboard,
+            color: Colors.white,
+            label: 'Dashboard',
+          ),
+          ...[]
+        ],
+      ),
+      body: Padding(
+        padding: const EdgeInsets.fromLTRB(16, 45, 16, 16),
+        child: Center(
+          child: ChangeNotifierProvider<AccountViewModel>(
+              create: (context) => AccountViewModel(),
+              child:
+                  Consumer<AccountViewModel>(builder: (context, value, child) {
+                // _checkResponse(value.response);
+                if (!widget.loggedOut) {
+                  _isLoggedIn(context);
+                }
+                return _loading
+                    ? const CircularProgressIndicator(
+                        color: Colors.grey,
+                      )
+                    : Column(
+                        children: [
+                          Image.asset(
+                            'lib/assets/logo_300x200.png',
+                          ),
+                          const SizedBox(
+                            height: 40,
+                          ),
+                          Text(
+                            'Digitale Spuren auf Knopfdruck entfernen'
+                                .toUpperCase(),
+                            textAlign: TextAlign.center,
+                            style: const TextStyle(
+                              fontFamily: 'sans-serif',
+                              fontSize: 24,
+                              height: 1.6,
+                              fontWeight: FontWeight.normal,
+                              letterSpacing: 6,
                             ),
-                            const SizedBox(
-                              height: 40,
-                            ),
-                            Text(
-                              'Digitale Spuren auf Knopfdruck entfernen'
-                                  .toUpperCase(),
-                              textAlign: TextAlign.center,
-                              style: const TextStyle(
-                                fontFamily: 'sans-serif',
-                                fontSize: 24,
-                                height: 1.6,
-                                fontWeight: FontWeight.normal,
-                                letterSpacing: 6,
-                              ),
-                            ),
-                          ],
-                        ),
-                ),
-              ),
-            );
-          },
+                          ),
+                        ],
+                      );
+              })),
         ),
       ),
-    );
+    ));
   }
 }
diff --git a/frontend/app/lib/pages/login_overlay.dart b/frontend/app/lib/pages/login_overlay.dart
index 927dc46..ef927a5 100644
--- a/frontend/app/lib/pages/login_overlay.dart
+++ b/frontend/app/lib/pages/login_overlay.dart
@@ -1,7 +1,12 @@
-import 'package:app/model/services/backend_service.dart';
+import 'package:app/model/view_model/base_vm.dart';
 import 'package:app/widgets/background.dart';
+import 'package:app/widgets/bottom_navigation.dart';
+import 'package:app/widgets/bottom_navigation_item.dart';
+import 'package:app/widgets/side_drawer.dart';
+import 'package:app/widgets/side_drawer_item.dart';
 import 'package:flutter/material.dart';
 import 'package:app/util/validation.dart';
+import 'package:provider/provider.dart';
 
 Future<bool> showLogin(BuildContext context,
     {bool registration = false}) async {
@@ -9,15 +14,17 @@ Future<bool> showLogin(BuildContext context,
   final mailController = TextEditingController();
   final passwordController = TextEditingController();
 
+  BaseViewModel vm = BaseViewModel();
   bool submitted = false;
   bool loggedin = false;
-  void login() {
+  void login(BuildContext context) {
     if (formKey.currentState!.validate()) {
       submitted = true;
-      BackendService.login(
-        email: mailController.text,
-        password: passwordController.text,
-      ).then(
+      FocusScope.of(context).unfocus();
+      vm
+          .login(context,
+              email: mailController.text, password: passwordController.text)
+          .then(
         (r) {
           if (r) {
             loggedin = r;
@@ -25,16 +32,21 @@ Future<bool> showLogin(BuildContext context,
           }
         },
       );
+      passwordController.clear();
+      submitted = false;
     }
   }
 
-  void register() {
+  void register(BuildContext context) {
     if (formKey.currentState!.validate()) {
       submitted = true;
-      BackendService.createAccount(
+      vm
+          .createAccount(
+        context,
         email: mailController.text,
         password: passwordController.text,
-      ).then(
+      )
+          .then(
         (r) {
           if (r) {
             loggedin = r;
@@ -52,120 +64,174 @@ Future<bool> showLogin(BuildContext context,
       context: context,
       builder: (builder) {
         return Background(
-          child: Column(
-            mainAxisAlignment: MainAxisAlignment.center,
-            children: [
-              const SizedBox(
-                height: 50,
-              ),
-              const Image(
-                width: 180,
-                image: AssetImage(
-                  'lib/assets/logo_300x200.png',
+          child: Scaffold(
+            drawer: SideDrawer(
+              children: [
+                const Spacer(
+                  flex: 3,
                 ),
-              ),
-              const SizedBox(
-                height: 30,
-              ),
-              Text(
-                registration ? 'Registrieren' : 'Login',
-                style: const TextStyle(
-                  fontFamily: 'sans-serif',
-                  fontSize: 24,
-                  height: 1.6,
-                  fontWeight: FontWeight.normal,
-                  letterSpacing: 6,
+                SideDrawerItem(
+                  onPressed: () {},
+                  icon: Icons.question_answer,
+                  color: Colors.white,
+                  label: 'About',
                 ),
-              ),
-              Form(
-                key: formKey,
-                child: Column(
-                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-                  crossAxisAlignment: CrossAxisAlignment.center,
-                  children: [
-                    const SizedBox(
-                      height: 40,
+                SideDrawerItem(
+                  onPressed: () {},
+                  icon: Icons.privacy_tip,
+                  color: Colors.white,
+                  label: 'Datenschutz',
+                ),
+                SideDrawerItem(
+                  onPressed: () {},
+                  icon: Icons.apartment,
+                  color: Colors.white,
+                  label: 'Impressum',
+                ),
+                const Spacer(
+                  flex: 1,
+                ),
+              ],
+            ),
+            bottomNavigationBar: BottomNavigation(
+              children: [
+                BottomNavigationItem(
+                  onPressed: () {
+                    Navigator.pop(context, false);
+                  },
+                  icon: Icons.arrow_back,
+                  color: Colors.white,
+                  label: 'Zurück',
+                ),
+                BottomNavigationItem(
+                  onPressed: () {
+                    Navigator.pop(context, false);
+                  },
+                  icon: Icons.home,
+                  color: Colors.white,
+                  label: 'Home',
+                ),
+              ],
+            ),
+            body: Padding(
+              padding: const EdgeInsets.all(16.0),
+              child: Column(
+                mainAxisAlignment: MainAxisAlignment.center,
+                children: [
+                  const SizedBox(
+                    height: 50,
+                  ),
+                  const Image(
+                    width: 180,
+                    image: AssetImage(
+                      'lib/assets/logo_300x200.png',
                     ),
-                    TextFormField(
-                      autofocus: true,
-                      // inputFormatters: [
-                      //   FilteringTextInputFormatter.allow(
-                      //     emailRegExp,
-                      //   ),
-                      // ],
-                      controller: mailController,
-                      decoration: const InputDecoration(
-                        fillColor: Color.fromARGB(30, 255, 255, 255),
-                        filled: true,
-                        hintStyle: TextStyle(
-                          color: Colors.white38,
-                        ),
-                        hintText: 'E-Mail Adresse',
-                      ),
-                      keyboardType: TextInputType.emailAddress,
-                      validator: (value) {
-                        if (value == null || !value.isValidEmail) {
-                          return 'Bitte eine gültige E-Mail Adresse eingeben';
-                        }
-                        return null;
-                      },
+                  ),
+                  const SizedBox(
+                    height: 30,
+                  ),
+                  Text(
+                    registration ? 'Registrieren' : 'Login',
+                    style: const TextStyle(
+                      fontFamily: 'sans-serif',
+                      fontSize: 24,
+                      height: 1.6,
+                      fontWeight: FontWeight.normal,
+                      letterSpacing: 6,
                     ),
-                    TextFormField(
-                      style: const TextStyle(
-                        color: Colors.white,
-                      ),
-                      // inputFormatters: [
-                      //   FilteringTextInputFormatter.allow(
-                      //     passwordRegExp,
-                      //   ),
-                      // ],
-                      controller: passwordController,
-                      decoration: const InputDecoration(
-                        fillColor: Color.fromARGB(30, 255, 255, 255),
-                        filled: true,
-                        hintStyle: TextStyle(
-                          color: Colors.white38,
-                        ),
-                        hintText: 'Passwort',
-                      ),
-                      keyboardType: TextInputType.visiblePassword,
-                      obscureText: true,
-                      validator: (value) {
-                        if (value == null || !value.isValidPassword) {
-                          return 'Bitte geben Sie Ihr Passwort ein';
-                        }
-                        return null;
-                      },
-                    ),
-                    const SizedBox(
-                      height: 15,
-                    ),
-                    Row(
-                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-                      children: [
-                        ElevatedButton(
-                          onPressed: !submitted
-                              ? () {
-                                  Navigator.pop(context);
+                  ),
+                  ChangeNotifierProvider<BaseViewModel>(
+                    create: (context) => BaseViewModel(),
+                    child: Consumer<BaseViewModel>(
+                      builder: (context, value, child) => Form(
+                        key: formKey,
+                        child: Column(
+                          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+                          crossAxisAlignment: CrossAxisAlignment.center,
+                          children: [
+                            const SizedBox(
+                              height: 40,
+                            ),
+                            TextFormField(
+                              // autofocus: true,
+                              // inputFormatters: [
+                              //   FilteringTextInputFormatter.allow(
+                              //     emailRegExp,
+                              //   ),
+                              // ],
+                              controller: mailController,
+                              decoration: const InputDecoration(
+                                fillColor: Color.fromARGB(30, 255, 255, 255),
+                                filled: true,
+                                hintStyle: TextStyle(
+                                  color: Colors.white38,
+                                ),
+                                hintText: 'E-Mail Adresse',
+                              ),
+                              keyboardType: TextInputType.emailAddress,
+                              validator: (value) {
+                                if (value == null || !value.isValidEmail) {
+                                  return 'Bitte eine gültige E-Mail Adresse eingeben';
                                 }
-                              : null,
-                          child: const Icon(Icons.arrow_back),
+                                return null;
+                              },
+                            ),
+                            TextFormField(
+                              style: const TextStyle(
+                                color: Colors.white,
+                              ),
+                              // inputFormatters: [
+                              //   FilteringTextInputFormatter.allow(
+                              //     passwordRegExp,
+                              //   ),
+                              // ],
+                              controller: passwordController,
+                              decoration: const InputDecoration(
+                                fillColor: Color.fromARGB(30, 255, 255, 255),
+                                filled: true,
+                                hintStyle: TextStyle(
+                                  color: Colors.white38,
+                                ),
+                                hintText: 'Passwort',
+                              ),
+                              keyboardType: TextInputType.visiblePassword,
+                              obscureText: true,
+                              validator: (value) {
+                                if (value == null || !value.isValidPassword) {
+                                  return 'Bitte geben Sie Ihr Passwort ein';
+                                }
+                                return null;
+                              },
+                            ),
+                            const SizedBox(
+                              height: 15,
+                            ),
+                            Row(
+                              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+                              children: [
+                                ElevatedButton(
+                                  onPressed: !submitted
+                                      ? !registration
+                                          ? () {
+                                              login(context);
+                                            }
+                                          : () {
+                                              register(context);
+                                            }
+                                      : null,
+                                  child: const Icon(Icons.login),
+                                ),
+                              ],
+                            )
+                          ],
                         ),
-                        ElevatedButton(
-                          onPressed: !submitted
-                              ? !registration
-                                  ? login
-                                  : register
-                              : null,
-                          child: const Icon(Icons.login),
-                        ),
-                      ],
-                    )
-                  ],
-                ),
+                      ),
+                    ),
+                  ),
+                  const Spacer(),
+                ],
               ),
-              const Spacer(),
-            ],
+            ),
           ),
         );
       });
diff --git a/frontend/app/lib/pages/persons_page.dart b/frontend/app/lib/pages/persons_page.dart
index 746dfad..d863dec 100644
--- a/frontend/app/lib/pages/persons_page.dart
+++ b/frontend/app/lib/pages/persons_page.dart
@@ -42,13 +42,23 @@ class _PersonsPageState extends State<PersonsPage> {
         response.message!.contains('unauthenticated')) {
       BackendService.logout();
       Navigator.of(context).pushAndRemoveUntil(
-          MaterialPageRoute(builder: (builder) => const HomePage()),
+          MaterialPageRoute(
+              builder: (builder) => HomePage(
+                    loggedOut: true,
+                  )),
           (route) => false);
     }
   }
 
   bool _loading = true;
   bool _loggedin = false;
+  List<Person> persons = [];
+
+  PersonsViewModel vm = PersonsViewModel();
+
+  void listPersons(BuildContext context) async {
+    persons = await vm.listPersons();
+  }
 
   List<Widget> _personsList(List<Person> persons) {
     final List<Widget> list = [];
@@ -67,106 +77,106 @@ class _PersonsPageState extends State<PersonsPage> {
   @override
   Widget build(BuildContext context) {
     return Background(
-      child: ChangeNotifierProvider<PersonsViewModel>(
-        create: (context) => PersonsViewModel(),
-        child: Consumer<PersonsViewModel>(
-          builder: (context, value, child) {
-            _checkResponse(value.response);
-            return Scaffold(
-              floatingActionButtonLocation:
-                  FloatingActionButtonLocation.centerFloat,
-              floatingActionButton: FloatingActionButton(
-                onPressed: () {},
-                child: const Icon(Icons.add),
+      child: Scaffold(
+        floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
+        floatingActionButton: FloatingActionButton(
+          onPressed: () {},
+          child: const Icon(Icons.add),
+        ),
+        appBar: AppBar(
+          automaticallyImplyLeading: false,
+        ),
+        drawer: SideDrawer(
+          children: [
+            const Spacer(
+              flex: 3,
+            ),
+            SideDrawerItem(
+              onPressed: () {},
+              icon: Icons.question_answer,
+              color: Colors.white,
+              label: 'About',
+            ),
+            SideDrawerItem(
+              onPressed: () {},
+              icon: Icons.privacy_tip,
+              color: Colors.white,
+              label: 'Datenschutz',
+            ),
+            SideDrawerItem(
+              onPressed: () {},
+              icon: Icons.apartment,
+              color: Colors.white,
+              label: 'Impressum',
+            ),
+            const Spacer(
+              flex: 1,
+            ),
+            if (_loggedin)
+              SideDrawerItem(
+                onPressed: () async {
+                  setState(() {
+                    _loading = true;
+                  });
+                  await BackendService.logout();
+                  // ignore: use_build_context_synchronously
+                  Navigator.of(context).pushAndRemoveUntil(
+                      MaterialPageRoute(
+                          builder: (builder) => HomePage(
+                                loggedOut: true,
+                              )),
+                      (route) => false);
+                  setState(() {
+                    _loggedin = false;
+                    _loading = false;
+                  });
+                },
+                icon: Icons.logout,
+                color: Colors.white,
+                label: 'Logout',
               ),
-              appBar: AppBar(
-                automaticallyImplyLeading: false,
-              ),
-              drawer: SideDrawer(
-                children: [
-                  const Spacer(
-                    flex: 3,
-                  ),
-                  SideDrawerItem(
-                    onPressed: () {},
-                    icon: Icons.question_answer,
-                    color: Colors.white,
-                    label: 'About',
-                  ),
-                  SideDrawerItem(
-                    onPressed: () {},
-                    icon: Icons.privacy_tip,
-                    color: Colors.white,
-                    label: 'Datenschutz',
-                  ),
-                  SideDrawerItem(
-                    onPressed: () {},
-                    icon: Icons.apartment,
-                    color: Colors.white,
-                    label: 'Impressum',
-                  ),
-                  const Spacer(
-                    flex: 1,
-                  ),
-                  if (_loggedin || value.response.data != null)
-                    SideDrawerItem(
-                      onPressed: () async {
-                        setState(() {
-                          _loading = true;
-                        });
-                        await BackendService.logout();
-                        // ignore: use_build_context_synchronously
-                        Navigator.of(context).pushAndRemoveUntil(
-                            MaterialPageRoute(
-                                builder: (builder) => const HomePage()),
-                            (route) => false);
-                        setState(() {
-                          _loggedin = false;
-                          _loading = false;
-                        });
-                      },
-                      icon: Icons.logout,
-                      color: Colors.white,
-                      label: 'Logout',
-                    ),
-                ],
-              ),
-              bottomNavigationBar: BottomNavigation(
-                children: [
-                  BottomNavigationItem(
-                    onPressed: () {},
-                    icon: Icons.dashboard,
-                    color: Colors.white,
-                    label: 'Dashboard',
-                  ),
-                  BottomNavigationItem(
-                    onPressed: () {
-                      Navigator.of(context).pop();
-                    },
-                    icon: Icons.home,
-                    color: Colors.white,
-                    label: 'Home',
-                  ),
-                ],
-              ),
-              body: Padding(
-                padding: const EdgeInsets.all(16),
-                child: Center(
-                  child: _loading
+          ],
+        ),
+        bottomNavigationBar: BottomNavigation(
+          children: [
+            BottomNavigationItem(
+              onPressed: () {},
+              icon: Icons.dashboard,
+              color: Colors.white,
+              label: 'Dashboard',
+            ),
+            BottomNavigationItem(
+              onPressed: () {
+                Navigator.of(context).pop();
+              },
+              icon: Icons.home,
+              color: Colors.white,
+              label: 'Home',
+            ),
+          ],
+        ),
+        body: Padding(
+          padding: const EdgeInsets.all(16),
+          child: Center(
+            child: ChangeNotifierProvider<PersonsViewModel>(
+              create: (context) => PersonsViewModel(),
+              child: Consumer<PersonsViewModel>(
+                builder: (context, value, child) {
+                  _checkResponse(value.response);
+                  listPersons(context);
+                  return _loading
                       ? const CircularProgressIndicator(
                           color: Colors.grey,
                         )
                       : value.response.status == Status.COMPLETED
                           ? value.response.data.length > 0
-                              ? ListView(
-                                  children: _personsList(
-                                      (value.response.data as List<Person>)))
+                              ? ListView(children: _personsList(persons))
                               : const Text('Noch keine Personen angelegt')
-                          : const Text('Lade Daten...'),
-                ),
+                          : const Text('Lade Daten...');
+                },
               ),
-            );
-          },
+            ),
+          ),
         ),
       ),
     );
diff --git a/frontend/app/lib/util/colors.dart b/frontend/app/lib/util/colors.dart
new file mode 100644
index 0000000..5c8d297
--- /dev/null
+++ b/frontend/app/lib/util/colors.dart
@@ -0,0 +1,11 @@
+import 'package:flutter/material.dart';
+
+class CustomColors {
+  static Color get error {
+    return const Color.fromARGB(200, 255, 90, 90);
+  }
+
+  static Color get success {
+    return const Color.fromARGB(200, 55, 125, 55);
+  }
+}
diff --git a/frontend/app/lib/widgets/bottom_navigation.dart b/frontend/app/lib/widgets/bottom_navigation.dart
index 25e74b9..c3f6519 100644
--- a/frontend/app/lib/widgets/bottom_navigation.dart
+++ b/frontend/app/lib/widgets/bottom_navigation.dart
@@ -1,5 +1,6 @@
 import 'package:flutter/material.dart';
 
+// ignore: must_be_immutable
 class BottomNavigation extends StatelessWidget {
   BottomNavigation({
     super.key,
diff --git a/frontend/app/lib/widgets/bottom_navigation_item.dart b/frontend/app/lib/widgets/bottom_navigation_item.dart
index 72f46c3..c6d6be4 100644
--- a/frontend/app/lib/widgets/bottom_navigation_item.dart
+++ b/frontend/app/lib/widgets/bottom_navigation_item.dart
@@ -1,5 +1,6 @@
 import 'package:flutter/material.dart';
 
+// ignore: must_be_immutable
 class BottomNavigationItem extends StatelessWidget {
   BottomNavigationItem({
     super.key,
diff --git a/frontend/app/lib/widgets/drawer.dart b/frontend/app/lib/widgets/drawer.dart
index 5ec955b..47343bb 100644
--- a/frontend/app/lib/widgets/drawer.dart
+++ b/frontend/app/lib/widgets/drawer.dart
@@ -1,13 +1,12 @@
-import 'package:app/pages/home_page.dart';
-import 'package:app/widgets/side_drawer_item.dart';
 import 'package:flutter/material.dart';
 
+// ignore: must_be_immutable
 class SideDrawer extends StatelessWidget {
   SideDrawer({super.key, required this.children, this.backgroundColor}) {
     backgroundColor ??= Colors.black;
   }
 
-  List<Widget> children;
+  final List<Widget> children;
   Color? backgroundColor;
 
   @override
diff --git a/frontend/app/lib/widgets/side_drawer_item.dart b/frontend/app/lib/widgets/side_drawer_item.dart
index 35668a4..b12e882 100644
--- a/frontend/app/lib/widgets/side_drawer_item.dart
+++ b/frontend/app/lib/widgets/side_drawer_item.dart
@@ -1,6 +1,6 @@
-import 'package:app/pages/home_page.dart';
 import 'package:flutter/material.dart';
 
+// ignore: must_be_immutable
 class SideDrawerItem extends StatelessWidget {
   SideDrawerItem({
     super.key,