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()insrc/cluster_erp/desktop/main.py:110-130.pyproject.toml:88also installs it as the console scriptcluster-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
desktopextra, 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:
main()configures logging and installs_global_exception_handlerassys.excepthook(src/cluster_erp/desktop/main.py:110-116)._run_app()removes attachment preview folders left by an earlier process, creates theQApplication, and picks the first installed font from a fixed list (src/cluster_erp/desktop/main.py:133-160).- It creates
SettingsStore,ThemeEngine, andAccessibilityManager, and applies the accessibility settings before any window exists (src/cluster_erp/desktop/main.py:162-165). - It creates
Translator, reads the server address from the settingapi_url, and createsApiClientwith the current language and theSignalBus(src/cluster_erp/desktop/main.py:166-175). LoginDialogruns modally. Closing it without signing in ends the process with exit code 0 (src/cluster_erp/desktop/main.py:182-190).- The client emits
user_logged_inand createsMetadataStore. 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). - It creates
FkCache, registers metadata labels with the translator, buildsMainWindow, 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
desktopextra: the comment inpyproject.toml:68-71states that a server node never installs a GUI toolkit. - Crash reporting: the docstring in
src/cluster_erp/desktop/main.py:48-49states 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
httpxsynchronous client withQThreadworkers and no async event loop, to avoid complexity.ApiClientwrapshttpx.Client(src/cluster_erp/desktop/core/api_client.py:86-91) andApiWorkersubclassesQThread(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 ofcluster_erp.modules,cluster_erp.core, orcluster_erp.serverreturns no match. The chat widget importscluster_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, andtests/test_order_shipment_chain.py:201(web and desktop prune the same metadata shapes). The probesweb-client/_desktop_visual.py,web-client/_desktop_survey.py,web-client/_desktop_tenant_fields.py, andweb-client/_desktop_intranet_check.pydrive 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/loginandPOST /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, andGET /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 /healthon 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¶
MainWindowand its status bar are created aftermain()emitsuser_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 asversioninpyproject.toml:7. The status bar shows it (src/cluster_erp/desktop/widgets/status_bar.py:73-75). - The package data in
pyproject.toml:93-95lists*.jsonand*.qssonly. The chat background images insrc/cluster_erp/desktop/widgets/chat/assets/are not listed. Whether a non-editable install includes them: Not determined from code. The package data inpyproject.tomlwas searched, and the repository has noMANIFEST.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 |
Related pages¶
- Desktop client
- Run the desktop client
- API client and workers
- Architecture overview
- Server start-up and app factory
Verified against commit 92f8051 on 2026-11-13.