Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,10 @@ AI_MODEL=llama-3.1-8b-instant
# 5. Business Logic & Limits
# ------------------------------------------------------------------------------
DAILY_INTERVIEW_LIMIT=10

# ------------------------------------------------------------------------------
# 6. Desktop Native Client Configuration (apps/desktop)
# ------------------------------------------------------------------------------
DEV_DIALOGUE_API_URL=http://localhost:5238
DEV_DIALOGUE_SUPABASE_URL=https://your-project.supabase.co
DEV_DIALOGUE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ node_modules/
.next/
out/
build/
build-*/
dist/
.cache/

Expand Down
116 changes: 113 additions & 3 deletions apps/desktop/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ find_package(Qt6 6.5 REQUIRED COMPONENTS

find_package(nlohmann_json 3.11.3 REQUIRED)

# Qt6Keychain: mandatory in Release (without QUIET), warning in Debug
if(CMAKE_BUILD_TYPE STREQUAL "Release")
find_package(Qt6Keychain REQUIRED)
else()
find_package(Qt6Keychain QUIET)
if(NOT Qt6Keychain_FOUND)
message(WARNING "Qt6Keychain not found in Debug mode. Falling back to in-memory secure storage.")
endif()
endif()

add_executable(DevDialogue
src/main.cpp

Expand All @@ -44,8 +54,28 @@ add_executable(DevDialogue

# Models & Contracts
include/models/ApiContracts.hpp

# Network
src/network/ApiClient.cpp
include/network/ApiClient.hpp
include/network/NetworkEndpoints.hpp

# Services & Secure Storage
include/services/ISecureStorage.hpp
src/services/InMemorySecureStorage.cpp
include/services/InMemorySecureStorage.hpp
src/services/QtKeychainSecureStorage.cpp
include/services/QtKeychainSecureStorage.hpp
src/services/AuthService.cpp
include/services/AuthService.hpp
src/services/InterviewService.cpp
include/services/InterviewService.hpp
src/services/AdminService.cpp
include/services/AdminService.hpp

# ViewModels
src/viewmodels/AuthViewModel.cpp
include/viewmodels/AuthViewModel.hpp
src/viewmodels/NavigationViewModel.cpp
include/viewmodels/NavigationViewModel.hpp
)
Expand All @@ -66,6 +96,14 @@ target_link_libraries(DevDialogue PRIVATE
nlohmann_json::nlohmann_json
)

if(TARGET qt6keychain)
target_link_libraries(DevDialogue PRIVATE qt6keychain)
target_compile_definitions(DevDialogue PRIVATE HAS_QTKEYCHAIN=1)
elseif(TARGET Qt6Keychain::Qt6Keychain)
target_link_libraries(DevDialogue PRIVATE Qt6Keychain::Qt6Keychain)
target_compile_definitions(DevDialogue PRIVATE HAS_QTKEYCHAIN=1)
endif()

if(WIN32)
target_link_libraries(DevDialogue PRIVATE Crypt32 Advapi32)
endif()
Expand All @@ -80,12 +118,84 @@ qt_add_qml_module(DevDialogue
qml/views/LandingView.qml
)

if(WIN32)
# ==========================================
# Testing (GoogleTest)
# ==========================================
find_package(GTest QUIET)
if(GTest_FOUND)
enable_testing()

add_executable(DevDialogueTests
tests/main.cpp
tests/helpers/MockHttpServer.hpp
tests/unit/TestApiContracts.cpp
tests/unit/TestSecureStorage.cpp
tests/unit/TestApiClient.cpp
tests/unit/TestAuthService.cpp

# Headers for AUTOMOC
include/core/AppConfig.hpp
include/core/Constants.hpp
include/models/ApiContracts.hpp
include/network/ApiClient.hpp
include/network/NetworkEndpoints.hpp
include/services/ISecureStorage.hpp
include/services/InMemorySecureStorage.hpp
include/services/QtKeychainSecureStorage.hpp
include/services/AuthService.hpp
include/services/InterviewService.hpp
include/services/AdminService.hpp

# Sources required for tests
src/core/AppConfig.cpp
src/network/ApiClient.cpp
src/services/InMemorySecureStorage.cpp
src/services/QtKeychainSecureStorage.cpp
src/services/AuthService.cpp
src/services/InterviewService.cpp
src/services/AdminService.cpp
)

target_include_directories(DevDialogueTests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}
)

target_link_libraries(DevDialogueTests PRIVATE
GTest::gtest
Qt6::Core
Qt6::Network
nlohmann_json::nlohmann_json
)

if(TARGET qt6keychain)
target_link_libraries(DevDialogueTests PRIVATE qt6keychain)
target_compile_definitions(DevDialogueTests PRIVATE HAS_QTKEYCHAIN=1)
elseif(TARGET Qt6Keychain::Qt6Keychain)
target_link_libraries(DevDialogueTests PRIVATE Qt6Keychain::Qt6Keychain)
target_compile_definitions(DevDialogueTests PRIVATE HAS_QTKEYCHAIN=1)
endif()

if(WIN32)
target_link_libraries(DevDialogueTests PRIVATE Crypt32 Advapi32)
endif()

include(GoogleTest)
gtest_discover_tests(DevDialogueTests
DISCOVERY_MODE PRE_TEST
PROPERTIES ENVIRONMENT "PATH=${CMAKE_BINARY_DIR}/vcpkg_installed/x64-windows/bin;$ENV{PATH}"
)
endif()

find_program(WINDEPLOYQT_EXECUTABLE windeployqt
HINTS "${Qt6_DIR}/../../../tools/Qt6/bin" "${Qt6_DIR}/../../../bin"
)

if(WIN32 AND WINDEPLOYQT_EXECUTABLE AND CMAKE_BUILD_TYPE STREQUAL "Release")
add_custom_command(TARGET DevDialogue POST_BUILD
COMMAND ${Qt6_DIR}/../../../bin/windeployqt.exe
COMMAND "${WINDEPLOYQT_EXECUTABLE}"
--qmldir ${CMAKE_CURRENT_SOURCE_DIR}/qml
$<TARGET_FILE:DevDialogue>
COMMENT "Deploying Qt runtime libraries with windeployqt..."
)
endif()

22 changes: 15 additions & 7 deletions apps/desktop/include/core/AppConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,25 @@ namespace devdialogue::core {

class AppConfig {
public:
AppConfig();
AppConfig();

std::string apiBaseUrl() const;
void setApiBaseUrl(const std::string &url);
std::string apiBaseUrl() const;
void setApiBaseUrl(const std::string& url);

bool isOfflineModeEnabled() const;
void setOfflineModeEnabled(bool enabled);
std::string supabaseUrl() const;
void setSupabaseUrl(const std::string& url);

std::string supabaseAnonKey() const;
void setSupabaseAnonKey(const std::string& key);

bool isOfflineModeEnabled() const;
void setOfflineModeEnabled(bool enabled);

private:
std::string m_apiBaseUrl;
bool m_offlineMode;
std::string m_apiBaseUrl;
std::string m_supabaseUrl;
std::string m_supabaseAnonKey;
bool m_offlineMode{false};
};

} // namespace devdialogue::core
16 changes: 11 additions & 5 deletions apps/desktop/include/core/Constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,17 @@ constexpr int DefaultWindowHeight = 800;
constexpr int MinWindowWidth = 960;
constexpr int MinWindowHeight = 640;

constexpr int NetworkTimeoutMs = 15000;
constexpr int HealthCheckIntervalMs = 30000;
// Network Timeouts (ms)
constexpr int ColdStartTimeoutMs = 90000; // 90 s for Render cold start and healthcheck
constexpr int StandardTimeoutMs = 30000; // 30 s for normal REST operations
constexpr int HealthCheckIntervalMs = 30000; // 30 s periodic heartbeat
constexpr int MaxGetRetries = 2; // Retries allowed only for GET requests
constexpr int WakingUpThresholdMs = 3000; // Trigger isWakingUp if request takes > 3s

constexpr std::string_view StorageKeyToken = "jwt_token";
constexpr std::string_view StorageKeyUser = "user_session";
constexpr std::string_view StorageKeyLanguage = "ui_language";
// Secure Storage Keys
inline constexpr const char* StorageKeyAccessToken = "jwt_token";
inline constexpr const char* StorageKeyRefreshToken = "refresh_token";
inline constexpr const char* StorageKeyUser = "user_session";
inline constexpr const char* StorageKeyLanguage = "ui_language";

} // namespace devdialogue::core::constants
Loading
Loading