A Cluster ERP deployment can declare the country it serves. The command python -m cluster_erp.server.residency_check then looks for anything in the configuration or in the control plane that contradicts that declaration. This page explains the rule behind it, every finding code, and the limits of the check. The settings themselves are listed in the configuration reference.
In short¶
- The declaration is
CLUSTER_ERP_NODE_COUNTRY, a two-letter ISO 3166-1 code; without it the command prints that no policy is declared and exits with code 0 (src/cluster_erp/server/residency_check.py:347-355,src/cluster_erp/config/settings.py:756-760). - With a declaration the command prints a summary, then either
CLEAN: nothing contradicts the declaration.with exit code 0 or the findings with exit code 1 (src/cluster_erp/server/residency_check.py:358-373). - The checks are pure functions over settings and tenant rows; only
collectreads the control plane (src/cluster_erp/server/residency_check.py:28-29,src/cluster_erp/server/residency_check.py:325-344). install.shruns the check after every install and refuses to report the release as live when it fails (deploy/install.sh:258-259).
How it works¶
main builds Settings, calls collect, and prints the result (src/cluster_erp/server/residency_check.py:347-373). collect runs config_findings and, on a multi-tenant node, adds tenant_findings over the (key, region) pairs of every tenant whose registration is not deleted (src/cluster_erp/server/residency_check.py:325-344).
Finding codes¶
Nineteen codes, counted as the Finding(...) constructors in residency_check.py.
| Code | Reported when | Source |
|---|---|---|
BACKUP-REMOTE |
backup_dir is a network path. |
src/cluster_erp/server/residency_check.py:106-114 |
BACKUP-RELATIVE |
backup_dir is a relative path. |
src/cluster_erp/server/residency_check.py:115-122 |
STORAGE-REMOTE |
The local storage path is a network path. | src/cluster_erp/server/residency_check.py:124-133 |
STORAGE-RELATIVE |
The local storage path is relative. | src/cluster_erp/server/residency_check.py:134-141 |
STORAGE-S3-REGION-UNREVIEWED |
The S3 backend keeps the shipped default region. | src/cluster_erp/server/residency_check.py:142-152 |
STORAGE-S3-ENDPOINT |
The S3 backend has no explicit endpoint. | src/cluster_erp/server/residency_check.py:153-160 |
MAIL-RELAY-CONTRADICTION |
An SMTP host is set while mail_relay_none is true. |
src/cluster_erp/server/residency_check.py:165-172 |
MAIL-RELAY-UNDECLARED |
No SMTP host and no declaration that the node sends no mail. | src/cluster_erp/server/residency_check.py:173-181 |
SIGNUP-RELAY-UNDECLARED |
Signup mail goes by SMTP but no signup SMTP host is set. | src/cluster_erp/server/residency_check.py:182-189 |
REGION-FOREIGN |
The node serves a region whose code is not the declared country. | src/cluster_erp/server/residency_check.py:194-204 |
REGION-DB-REMOTE |
A region's database server is another host; the operator must confirm its country. | src/cluster_erp/server/residency_check.py:205-212 |
ARCHIVE-REMOTE |
wal_archive_dir or cold_storage_dir is a network path. |
src/cluster_erp/server/residency_check.py:213-227 |
ARCHIVE-RELATIVE |
wal_archive_dir or cold_storage_dir is relative. |
src/cluster_erp/server/residency_check.py:228-234 |
MAIL-RELAY-COUNTRY-UNDECLARED |
An SMTP relay is set but mail_relay_country is empty. |
src/cluster_erp/server/residency_check.py:235-244 |
MAIL-RELAY-ABROAD |
mail_relay_country differs from the declared country. |
src/cluster_erp/server/residency_check.py:245-252 |
STORAGE-S3-UNAVAILABLE |
The S3 backend is chosen but the S3 client library is not installed. | src/cluster_erp/server/residency_check.py:253-263 |
MAIL-PROVIDERS-EXTERNAL |
Mailbox linking to an external provider is configured. | src/cluster_erp/server/residency_check.py:264-292 |
COUNTRY-NODES-EMPTY |
CLUSTER_ERP_COUNTRY_NODES is empty. |
src/cluster_erp/server/residency_check.py:293-302 |
TENANT-FOREIGN-REGION |
A tenant is registered with a region that this node does not serve. | src/cluster_erp/server/residency_check.py:305-322 |
A path counts as absolute when it is absolute in either the POSIX or the Windows convention, and as remote when it starts with two slashes after backslashes are turned into slashes (src/cluster_erp/server/residency_check.py:55-72).
Why it is built this way¶
- The module states the policy: a customer's data stays in that customer's country, stored and processed there, so a deployment is one complete node per country (
src/cluster_erp/server/residency_check.py:5-9). - Code cannot verify geography, so the check reports only contradictions with the declaration (
src/cluster_erp/server/residency_check.py:11-14).
Rules and boundaries¶
Settingsalready refuses a country code that is not two letters, and aCLUSTER_ERP_COUNTRY_NODESmap that omits the node's own country (src/cluster_erp/config/settings.py:756-767).- The tests are in
tests/test_residency_check.py; the browser suite isweb-client/_e2e_residency.mjs.
Interaction with other parts¶
- The signup entry form and the operator console read
node_countryandcountry_nodesto send a customer to the node of their country (src/cluster_erp/server/routes/signup.py:126-138,src/cluster_erp/server/routes/vendor.py:157). See signup. - The backup, storage, and archive settings it checks are described in backups and restore.
Limits and open points¶
- A drive letter mapped to a remote share reads as local; the module leaves that gap to the operator (
src/cluster_erp/server/residency_check.py:25-26). - The check does not resolve host names or look up where an address is located;
REGION-DB-REMOTEasks the operator to confirm (src/cluster_erp/server/residency_check.py:205-212).
Terms introduced¶
| Term | Code identifier | Definition | Turkish term | Source |
|---|---|---|---|---|
| residency finding | Finding |
One way the deployment contradicts its declared country, with a code and a detail. | ikamet bulgusu | src/cluster_erp/server/residency_check.py:44-52 |
| node country | node_country |
The country a node declares it serves. | düğüm ülkesi | src/cluster_erp/config/settings.py:111 |
Related pages¶
Verified against commit 92f8051 on 2026-11-13.