Factorizer/Cluster ERP WikiCluster ERP Türkçe
Home / Desktop client

Explanation

Desktop client overview

What the PySide6 desktop client in src/cluster_erp/desktop is, how it starts, signs in, loads metadata, and which packaging and Qt version rules apply.

The desktop client is a Qt application in src/cluster_erp/desktop/ that talks to a Cluster ERP server over its HTTP API. This page explains its folder layout, the start-up and sign-in sequence in desktop/main.py, the desktop install extra, and the PySide6 version note. Each part of the client has its own page in the desktop section. How to start it is on run the desktop client.

In short

  • The entry point is main() in src/cluster_erp/desktop/main.py:110-130. pyproject.toml:88 also installs it as the console script cluster-erp-desktop.
  • Start-up creates the settings store, the theme engine, accessibility, the translator, the API client, and the signal bus, then shows the sign-in dialog (src/cluster_erp/desktop/main.py:162-190).
  • After sign-in the client loads the server metadata, with up to three attempts, and exits if all fail (src/cluster_erp/desktop/main.py:194-222).
  • Screens are built from metadata by the generic widgets. Ten section keys map to hand-written screens (src/cluster_erp/desktop/widgets/main_window.py:501-528).
  • PySide6 is an optional dependency in the desktop extra, so a server install carries no GUI toolkit (pyproject.toml:68-74).

How it works

Folder layout

The package has five folders. The counts below were made by listing src/cluster_erp/desktop/ at the verified commit: 86 Python files, of which 69 are not empty, with 34,331 lines of Python in total.

Folder Holds Page
core/ API client, worker threads, generic API, signal bus, metadata store, foreign-key cache, tab manager, pane controller, settings store, accessibility, time-zone helpers, preview files API client and workers
i18n/ translator.py, en.json, tr.json Languages, themes, and accessibility
themes/ theme_engine.py, style.qss Languages, themes, and accessibility
widgets/ Main window, sidebar, status bar, panes, dialogs, and the common/, generic/, and chat/ widget folders Generic widgets
modules/ Hand-written screens in bom, calendars, inventory, logs, procurement, production, and an empty purchasing_quotations package Module screens

Start-up and sign-in sequence

The diagram shows the path from main() to the visible main window.

sequenceDiagram
  participant M as main
  participant L as LoginDialog
  participant A as ApiClient
  participant S as Server
  participant MS as MetadataStore
  participant W as MainWindow
  M->>M: purge_stale_previews, QApplication, font
  M->>M: SettingsStore, ThemeEngine, AccessibilityManager, Translator
  M->>A: ApiClient(api_url), set_language, set_signal_bus
  M->>L: exec
  L->>A: login in ApiWorker
  A->>S: POST /auth/login
  S-->>A: tokens, user, permissions
  L-->>M: Accepted
  M->>MS: load, up to 3 attempts
  MS->>S: GET /_meta, /_switches, /_overlay, /app_store/registry
  M->>W: MainWindow, show, restore_pane_layout
  M->>M: app.exec

In words:

  1. main() configures logging and installs _global_exception_handler as sys.excepthook (src/cluster_erp/desktop/main.py:110-116).
  2. _run_app() removes attachment preview folders left by an earlier process, creates the QApplication, and picks the first installed font from a fixed list (src/cluster_erp/desktop/main.py:133-160).
  3. It creates SettingsStore, ThemeEngine, and AccessibilityManager, and applies the accessibility settings before any window exists (src/cluster_erp/desktop/main.py:162-165).
  4. It creates Translator, reads the server address from the setting api_url, and creates ApiClient with the current language and the SignalBus (src/cluster_erp/desktop/main.py:166-175).
  5. LoginDialog runs modally. Closing it without signing in ends the process with exit code 0 (src/cluster_erp/desktop/main.py:182-190).
  6. The client emits user_logged_in and creates MetadataStore. A failed load shows a retry question. After the third failure, or a cancel, a final error appears and the process exits with code 1 (src/cluster_erp/desktop/main.py:192-222).
  7. It creates FkCache, registers metadata labels with the translator, builds MainWindow, shows it, and restores the saved pane layout (src/cluster_erp/desktop/main.py:224-238).

Error handling

_global_exception_handler logs the traceback, posts it to POST /logs/errors/client with platform set to desktop, and shows a dialog with the technical detail behind a details button (src/cluster_erp/desktop/main.py:45-107). A flag stops the report from recursing if the report itself fails (src/cluster_erp/desktop/main.py:50-68). A failure during start-up shows the traceback in a critical message box and exits with code 1 (src/cluster_erp/desktop/main.py:118-130).

Packaging and Qt version

The desktop extra adds PySide6>=6.7.0. The comment above it states that the extra keeps the GUI toolkit off server nodes, that 6.8.3 is the known-good release on Windows, and that 6.11.0 fails with a DLL error (pyproject.toml:68-74). The CI lint job installs PySide6==6.8.3 so that mypy src also checks the client (.github/workflows/ci.yml:48-50). The package data ships the language files and the stylesheet (pyproject.toml:93-95).

Why it is built this way

  • The desktop extra: the comment in pyproject.toml:68-71 states that a server node never installs a GUI toolkit.
  • Crash reporting: the docstring in src/cluster_erp/desktop/main.py:48-49 states that a client crash lands in the same error log as server-side errors.
  • Synchronous HTTP with worker threads: the project's written engineering rules state that the client uses an httpx synchronous client with QThread workers and no async event loop, to avoid complexity. ApiClient wraps httpx.Client (src/cluster_erp/desktop/core/api_client.py:86-91) and ApiWorker subclasses QThread (src/cluster_erp/desktop/core/api_worker.py:28).

Rules and boundaries

  • The client imports no backend module package. A search of src/cluster_erp/desktop/ for imports of cluster_erp.modules, cluster_erp.core, or cluster_erp.server returns no match. The chat widget imports cluster_erp.ai (src/cluster_erp/desktop/widgets/chat/chat_widget.py:47); see chat widget.
  • Every refresh between screens goes through the client-side SignalBus; see signal bus and watch_entity.
  • Tests pin parts of the client: tests/test_desktop_app_scope.py, tests/test_desktop_datetime_field.py, tests/test_desktop_table_text_insets.py, and tests/test_order_shipment_chain.py:201 (web and desktop prune the same metadata shapes). The probes web-client/_desktop_visual.py, web-client/_desktop_survey.py, web-client/_desktop_tenant_fields.py, and web-client/_desktop_intranet_check.py drive the real widgets on the offscreen Qt platform. They are listed in developer tools and scripts.

Interaction with other parts

  • Sign-in uses POST /auth/login and POST /auth/refresh (src/cluster_erp/desktop/core/api_client.py:134-205). The server side is described on authentication and sessions.
  • Metadata comes from GET /_meta, GET /_switches, GET /_overlay, and GET /app_store/registry (src/cluster_erp/desktop/core/metadata_store.py:19-82). The contract is described on metadata model.
  • The connection indicator calls GET /health on the server root every 15 seconds (src/cluster_erp/desktop/widgets/status_bar.py:49-63, src/cluster_erp/desktop/core/api_client.py:326-333).

Limits and open points

  • MainWindow and its status bar are created after main() emits user_logged_in (src/cluster_erp/desktop/main.py:192, src/cluster_erp/desktop/main.py:227-236). The status bar connects to that signal in its constructor (src/cluster_erp/desktop/widgets/status_bar.py:44), so the signed-in user name is not shown after the first sign-in. It is shown after a sign-in that follows an expired session (src/cluster_erp/desktop/widgets/main_window.py:263-264).
  • The application version is set to the literal 0.1.0 (src/cluster_erp/desktop/main.py:150), the same value as version in pyproject.toml:7. The status bar shows it (src/cluster_erp/desktop/widgets/status_bar.py:73-75).
  • The package data in pyproject.toml:93-95 lists *.json and *.qss only. The chat background images in src/cluster_erp/desktop/widgets/chat/assets/ are not listed. Whether a non-editable install includes them: Not determined from code. The package data in pyproject.toml was searched, and the repository has no MANIFEST.in.

Terms introduced

Term Code identifier Definition Turkish term Source
desktop client cluster_erp.desktop The PySide6 application that uses the HTTP API of a Cluster ERP server. masaüstü istemci src/cluster_erp/desktop/main.py:110
desktop extra desktop The optional dependency group that installs PySide6. desktop ek paketi pyproject.toml:72
global exception handler _global_exception_handler The hook that logs, reports, and shows any unhandled exception. genel hata yakalayıcı src/cluster_erp/desktop/main.py:71

Verified against commit 92f8051 on 2026-11-13.

Verified against commit 92f8051 · 2026-11-13