# Fincept Terminal Screen Service Architecture Pattern: Complete Technical Guide

> Explore Fincept Terminal's screen service architecture pattern. Learn how UI screens and business logic separate for modular and testable desktop apps using Qt signals slots.

- Repository: [Fincept Corporation/FinceptTerminal](https://github.com/Fincept-Corporation/FinceptTerminal)
- Tags: architecture
- Published: 2026-04-20

---

**Fincept Terminal implements a strict Screen↔Service separation pattern built on Qt’s signal/slot mechanism, where UI screens in `fincept-qt/src/screens/*` handle purely presentational concerns while business logic resides in `fincept-qt/src/services/*`, communicating via the `ScreenRouter` and `EventBus` for modular, testable desktop architecture.**

The Fincept-Corporation/FinceptTerminal repository demonstrates a sophisticated **screen service architecture pattern** that cleanly isolates user interface rendering from business logic using Qt’s framework capabilities. This architecture, documented in [`docs/ARCHITECTURE.md`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/docs/ARCHITECTURE.md), enables the financial terminal to maintain responsive UIs while executing heavy computational tasks asynchronously. By preventing screens from directly accessing `HttpClient`, `PythonRunner`, or database layers, the codebase achieves clear module boundaries and comprehensive testability.

## UI Layer: The Screen Abstraction

Screens reside in `fincept-qt/src/screens/*` and represent pure Qt widgets responsible solely for data presentation and user input capture. Each screen emits signals when user interactions occur but never executes business logic directly.

The [`MarketsScreen.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/MarketsScreen.cpp) implementation exemplifies this pattern. According to the source code (lines 37‑44), screens connect to services exclusively through Qt signals and slots, delegating all data fetching to service layers. Screens never instantiate HTTP clients, execute Python scripts, or manage caching strategies.

This separation ensures that UI components remain lightweight and focused on rendering, while the complexity of external API calls and data processing remains encapsulated elsewhere.

## Application Layer: Service Architecture

Services live in `fincept-qt/src/services/*` and encapsulate all non‑UI operations including network requests, script execution, and data persistence. The [`MarketDataService.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/MarketDataService.cpp) implementation (lines 59‑93) demonstrates how services handle batch request optimization, caching layers, and Python integration.

Services expose clean APIs that screens can invoke, such as `MarketDataService::fetch_quotes()`, which accepts a symbol list and callback. Internally, services utilize `HttpClient`, `PythonRunner`, SQLite, and `QThread`/`QtConcurrent` for asynchronous processing, then deliver results back to the UI thread via thread‑safe mechanisms.

This architecture creates a clear boundary where `MarketsScreen` calls `MarketDataService::instance().fetch_quotes()` without knowing whether data comes from cache, HTTP endpoints, or Python calculations.

## Navigation and Lazy Loading

The `ScreenRouter` class ([`fincept-qt/src/app/ScreenRouter.h`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/app/ScreenRouter.h) and [`fincept-qt/src/app/ScreenRouter.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/app/ScreenRouter.cpp)) manages view transitions using a `QStackedWidget` container. It supports two registration strategies:

- **Eager registration** via `register_screen()` constructs widgets immediately during application startup
- **Lazy registration** via `register_factory()` defers widget construction until first navigation, significantly reducing startup latency

Lazy factories prove essential for complex financial terminals where instantiating all screens upfront would degrade performance. The router handles lifecycle management while maintaining the separation between navigation logic and screen content.

## Cross‑Layer Communication Mechanisms

Screens and services communicate through two primary channels. **Direct signal/slot connections** allow services to push updates to specific screens, as implemented in [`MarketsScreen.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/MarketsScreen.cpp) lines 37‑44. **Broadcast messaging** occurs through `EventBus::instance().publish(...)` ([`fincept-qt/src/core/events/EventBus.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/core/events/EventBus.cpp)), enabling decoupled communication where multiple screens can react to service state changes without direct wiring.

Thread safety remains critical in this pattern. UI code runs exclusively on the main thread, while services offload heavy work to background threads. Results return to the UI via `QMetaObject::invokeMethod` or cross‑thread signal/slot connections, preventing blocking operations from freezing the interface.

## Error Handling and Infrastructure

All modules employ the `Result<T>` wrapper defined in [`fincept-qt/src/core/result/Result.h`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/core/result/Result.h) for explicit error propagation. This eliminates exception‑based control flow in favor of typed returns that callers must handle explicitly.

Structured logging occurs through `LOG_INFO` and `LOG_ERROR` macros defined in [`core/logging/Logger.h`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/core/logging/Logger.h), providing consistent observability across screens and services. Combined with the threading model—main thread for UI, `QThread` for services—this infrastructure supports robust financial data processing without compromising interface responsiveness.

## Implementation Example

The following code illustrates the strict separation between UI screens and business services:

```cpp
// fincept-qt/src/screens/markets/MarketsScreen.cpp – UI layer
void MarketsScreen::refresh_all() {
    // Screen delegates entirely to service, receives callback
    MarketDataService::instance().fetch_quotes({"AAPL", "MSFT"},
        [this](bool ok, QVector<QuoteData> quotes) {
            if (!ok) return;
            for (const auto& q : quotes) {
                update_panel(q.symbol, q.price, q.change_pct);
            }
        });
}

```

```cpp
// fincept-qt/src/services/markets/MarketDataService.cpp – Service layer
void MarketDataService::fetch_quotes(const QStringList& symbols,
                                    QuoteCallback cb) {
    // Implementation handles caching, HTTP batching, 
    // Python script execution (lines 59‑93), then invokes 
    // callback on UI thread with results.
}

```

The screen never accesses `HttpClient` or `PythonRunner`; it invokes the service façade and receives data through the provided callback mechanism.

## Summary

- **Screen↔Service separation** creates strict boundaries between `fincept-qt/src/screens/*` (UI) and `fincept-qt/src/services/*` (business logic)
- **Qt signals/slots** and `EventBus` provide decoupled communication channels without direct dependencies
- **ScreenRouter** manages navigation with eager and lazy registration strategies to optimize startup performance
- **Thread safety** ensures UI responsiveness through `QThread`/`QtConcurrent` in services and `QMetaObject::invokeMethod` for results
- **Result<T>** wrappers and structured logging macros provide robust error handling across all layers

## Frequently Asked Questions

### How does Fincept Terminal handle thread safety between screens and services?

UI code runs exclusively on the main thread while services execute heavy operations in `QThread` or `QtConcurrent` workers. Services return results to screens using `QMetaObject::invokeMethod` or cross‑thread signal/slot connections, ensuring the UI never blocks during HTTP requests or Python script execution.

### What is the difference between eager and lazy screen registration in ScreenRouter?

`register_screen` creates widget instances immediately during application initialization, suitable for frequently accessed views. `register_factory` stores factory functions that defer construction until first navigation, reducing startup time and memory footprint for complex terminal interfaces with many potential screens.

### How does the EventBus differ from direct signal/slot connections?

Direct signal/slot connections in [`MarketsScreen.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/MarketsScreen.cpp) (lines 37‑44) create point‑to‑point communication between specific screens and services. The `EventBus` ([`fincept-qt/src/core/events/EventBus.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/core/events/EventBus.cpp)) enables broadcast messaging where services publish events without knowing which screens subscribe, supporting one‑to‑many updates and decoupled module dependencies.

### What error handling mechanism does Fincept Terminal use for service operations?

All service methods return `Result<T>` types defined in [`fincept-qt/src/core/result/Result.h`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/core/result/Result.h) rather than throwing exceptions. This explicit error handling pattern forces callers to check success/failure states, while `LOG_INFO` and `LOG_ERROR` macros in [`core/logging/Logger.h`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/core/logging/Logger.h) capture structured diagnostic information for debugging.