The auth module in src/cluster_erp/modules/auth/ signs users in and decides what they may do. It manages users, roles, permission codes, attribute policies, approval chains and requests, notification rules, revoked tokens, and each user's own interface state. Administrators use its screens; every other module uses it through modules/auth/guards.py and the EventBus. The mechanisms are explained on the pages of the identity and access section; this page is the module overview.
At a glance¶
| Item | Value | Source |
|---|---|---|
| Package | src/cluster_erp/modules/auth/ |
folder |
| Module class | Module |
src/cluster_erp/modules/auth/module.py:15 |
name / version |
auth / 0.1.0 |
src/cluster_erp/modules/auth/module.py:16-22 |
| API prefix | /api/v1/auth (ModuleBase.api_prefix) |
src/cluster_erp/core/module_base.py:37-38 |
| Sub-modules | 10: approval_chains, approvals, login, notification_rules, permissions, policies, roles, token_blacklist, ui_state, users |
folder listing |
| Tables | 14 (__tablename__ count), plus auth_login_budget created by migration auth05 without a model |
grep over the package, migrations/versions/auth05_login_budget.py:33 |
| Entities in metadata | 6: user, role, abac_policy, approval_chain, approval_step, notification_rule |
src/cluster_erp/modules/auth/module.py:281-288 |
| Web app presence | Covered by the system app settings in the catalogue |
src/cluster_erp/modules/app_store/catalog.json (entry settings) |
| Desktop presence | Generic widgets only; no folder in src/cluster_erp/desktop/modules/ |
folder |
What the module does¶
- Signs users in and out and issues, rotates, and revokes tokens; see authentication and sessions.
- Keeps the permission catalogue, roles, and user-role assignments and guards every route; see roles and permissions.
- Stores attribute policies that refine a permission; see ABAC policies.
- Runs approval chains for other modules; see approvals and approval chains.
- Stores notification rules; see notification rules.
- Stores each user's layout and preferences on the server (
src/cluster_erp/modules/auth/ui_state/models.py:13-35); see user UI state.
Sub-modules¶
| Sub-module | Purpose | Main entities | Router | Source |
|---|---|---|---|---|
login |
Sign-in, refresh, sign-out, current user | none | /api/v1/auth |
src/cluster_erp/modules/auth/login/routes.py:51 |
users |
User accounts, password change and reset | AuthUser, AuthUserRole |
/api/v1/auth/users |
src/cluster_erp/modules/auth/users/routes.py:23 |
roles |
Roles and their grants | AuthRole, AuthRolePermission |
/api/v1/auth/roles |
src/cluster_erp/modules/auth/roles/routes.py:20 |
permissions |
Read the permission catalogue | AuthPermission |
/api/v1/auth/permissions |
src/cluster_erp/modules/auth/permissions/routes.py:11 |
policies |
ABAC policies | AuthAbacPolicy |
/api/v1/auth/policies |
src/cluster_erp/modules/auth/policies/routes.py:15 |
approval_chains |
Chains and steps | AuthApprovalChain, AuthApprovalStep |
/api/v1/auth/approval-chains, /api/v1/auth/approval-steps |
src/cluster_erp/modules/auth/approval_chains/routes.py:20-24 |
approvals |
Requests, decisions, defer | AuthApprovalRequest, AuthApprovalDecision, AuthApprovalSnooze |
/api/v1/auth/approvals |
src/cluster_erp/modules/auth/approvals/routes.py:22 |
notification_rules |
Notification rule records | NotificationRule |
/api/v1/auth/notification-rules |
src/cluster_erp/modules/auth/notification_rules/routes.py:21 |
token_blacklist |
Revoked token ids | TokenBlacklist |
none | src/cluster_erp/modules/auth/token_blacklist/models.py:11 |
ui_state |
Per-user interface state | UserUiState |
/api/v1/auth/ui-state |
src/cluster_erp/modules/auth/ui_state/routes.py:13-39 |
All routers are included under one module router (src/cluster_erp/modules/auth/module.py:32-70).
Data model¶
| Entity | Table | Key fields | Notes | Source |
|---|---|---|---|---|
AuthUser |
auth_users |
username, email, password_hash, is_active, failed_login_count, locked_until, last_logout_at, employee_id |
user name and e-mail unique among live rows | src/cluster_erp/modules/auth/users/models.py:17-91 |
AuthUserRole |
auth_user_roles |
user_id, role_id |
unique pair among live rows | src/cluster_erp/modules/auth/users/models.py:94-123 |
AuthRole |
auth_roles |
code, name, is_system, is_active |
code unique among live rows | src/cluster_erp/modules/auth/roles/models.py:17-65 |
AuthRolePermission |
auth_role_permissions |
role_id, permission_id |
unique pair among live rows | src/cluster_erp/modules/auth/roles/models.py:68-97 |
AuthPermission |
auth_permissions |
code, resource, action, module |
code unique among live rows | src/cluster_erp/modules/auth/permissions/models.py:15-55 |
AuthAbacPolicy |
auth_abac_policies |
code, permission_code, condition, is_active |
condition is JSONB |
src/cluster_erp/modules/auth/policies/models.py:12-55 |
AuthApprovalChain |
auth_approval_chains |
code, resource, action, is_active |
src/cluster_erp/modules/auth/approval_chains/models.py:13-61 |
|
AuthApprovalStep |
auth_approval_steps |
chain_id, step_order, role_code |
unique step_order per chain |
src/cluster_erp/modules/auth/approval_chains/models.py:64-106 |
AuthApprovalRequest |
auth_approval_requests |
chain_id, entity_type, entity_id, current_step, status, requested_by |
src/cluster_erp/modules/auth/approvals/models.py:26-74 |
|
AuthApprovalDecision |
auth_approval_decisions |
request_id, step_id, decided_by, decision |
src/cluster_erp/modules/auth/approvals/models.py:77-112 |
|
AuthApprovalSnooze |
auth_approval_snoozes |
request_id, user_id, until |
one live row per request and user | src/cluster_erp/modules/auth/approvals/models.py:115-156 |
NotificationRule |
platform_notification_rules |
event_type, recipient_type, channel, template_key |
src/cluster_erp/modules/auth/notification_rules/models.py:9-44 |
|
TokenBlacklist |
auth_token_blacklist |
token_jti, expires_at |
token_jti unique |
src/cluster_erp/modules/auth/token_blacklist/models.py:11-23 |
UserUiState |
auth_user_ui_state |
user_id, key, value |
one live row per user and key | src/cluster_erp/modules/auth/ui_state/models.py:13-35 |
Every entity derives from BaseModel, so rows are soft-deleted; see soft delete and deactivation.
Screens and metadata¶
get_metadata declares one sidebar group, Authorization in English and Yetkilendirme in Turkish, with three sections: Users (list of user), Roles (list of role), and Settings with the tabs abac_policy, approval_chain, and notification_rule (src/cluster_erp/modules/auth/module.py:236-280). The labels come from metadata, not from the language files. The approver inbox My Approvals (webapp/i18n/en.json key approvals.inbox_title) is a home widget of the web app; see home widgets.
Status and actions¶
The auth metadata declares no ActionMeta; a grep for ActionMeta( in modules/auth finds none. Approval requests change status through their own routes; see approvals and approval chains.
| Action | Label | Condition | Endpoint | Permission | Source |
|---|---|---|---|---|---|
| decide | Approve or Reject (approvals.approve, approvals.reject) |
request pending, caller holds the step role |
POST /api/v1/auth/approvals/{request_id}/decide |
step role, checked in the service | src/cluster_erp/modules/auth/approvals/routes.py:90-131 |
| defer | Defer (approvals.defer) |
request pending, caller eligible |
POST /api/v1/auth/approvals/{request_id}/defer |
step role, checked in the service | src/cluster_erp/modules/auth/approvals/routes.py:134-154 |
| cancel | none in metadata | request pending, caller is the requester or an administrator |
POST /api/v1/auth/approvals/{request_id}/cancel |
checked in the service | src/cluster_erp/modules/auth/approvals/routes.py:171-186 |
Business rules¶
- A system role cannot be deleted (
src/cluster_erp/modules/auth/roles/routes.py:104-105,src/cluster_erp/modules/auth/roles/services.py:72-80). - Role and permission grants obey the privilege ceiling (
src/cluster_erp/modules/auth/users/services.py:205-221,src/cluster_erp/modules/auth/roles/services.py:139-163). - Creating a user with a taken user name answers a conflict (
src/cluster_erp/modules/auth/users/routes.py:104-106). - The first administrator is created only on an empty database (
src/cluster_erp/modules/auth/users/services.py:412-453). - A changed password ends all earlier sessions (
src/cluster_erp/modules/auth/users/services.py:273-276).
Events and queries¶
| Direction | Contract class | Handler or emitter | Source |
|---|---|---|---|
| answers query | GetUserById |
_handle_get_user |
src/cluster_erp/modules/auth/module.py:81, src/cluster_erp/modules/auth/module.py:110-128 |
| answers query | GetUserPermissions |
_handle_get_permissions |
src/cluster_erp/modules/auth/module.py:82, src/cluster_erp/modules/auth/module.py:130-144 |
| answers query | GetApprovalChainForAction |
_handle_get_approval_chain |
src/cluster_erp/modules/auth/module.py:83-86 |
| answers query | SubmitForApproval |
_handle_submit_for_approval |
src/cluster_erp/modules/auth/module.py:87 |
| answers query | GetApprovalRequestById |
_handle_get_approval_request |
src/cluster_erp/modules/auth/module.py:88-91 |
| emits | ApprovalCompleted |
decide_approval |
src/cluster_erp/modules/auth/approvals/routes.py:116-127 |
| subscribes | CollectSubjectData |
collect_subject_data |
src/cluster_erp/modules/auth/module.py:101-104 |
| subscribes | AnonymiseSubject |
anonymise_subject |
src/cluster_erp/modules/auth/module.py:105-108 |
Permissions¶
| Permission key | Used by | Source |
|---|---|---|
user.read, user.create, user.update, user.delete, user.reset_password |
user routes | src/cluster_erp/modules/auth/users/routes.py:59-194 |
role.read, role.create, role.update, role.delete |
role routes | src/cluster_erp/modules/auth/roles/routes.py:42-119 |
permission.read, permission.assign |
catalogue, grants, approval reads and request creation | src/cluster_erp/modules/auth/permissions/routes.py:18, src/cluster_erp/modules/auth/roles/routes.py:122-150, src/cluster_erp/modules/auth/approvals/routes.py:27-80 |
abac_policy.read, abac_policy.create, abac_policy.update, abac_policy.delete |
policy routes | src/cluster_erp/modules/auth/policies/routes.py:18-87 |
approval_chain.read, approval_chain.create, approval_chain.update, approval_chain.delete |
chain and step routes | src/cluster_erp/modules/auth/approval_chains/routes.py:32-181 |
notification_rule.read, notification_rule.create, notification_rule.update, notification_rule.delete |
notification rule routes | src/cluster_erp/modules/auth/notification_rules/routes.py:24-93 |
user.reset_password is not a CRUD code; it is in the extra seed list (src/cluster_erp/server/app.py:675). The admin role receives every seeded code (src/cluster_erp/modules/auth/roles/services.py:213-276).
Privacy, retention, and history¶
privacy_handlers.py returns the sign-in account (user name, e-mail, names, active flag, role codes, sign-in and sign-out times, creation time) and, on erasure, overwrites identifying columns, deactivates the account, and stamps last_logout_at (src/cluster_erp/modules/auth/privacy_handlers.py:1-104). The password hash is never exported and is redacted in change history (src/cluster_erp/modules/auth/privacy_handlers.py:7-8). Expired blacklist rows are deleted by the daily log retention (src/cluster_erp/server/app.py:1168-1192). auth_token_blacklist is excluded from change history; see change history.
Analytics facts¶
This module has no analytics_facts.py.
Settings and reference data¶
Settings used by the module: secret_key, jwt_access_expire_minutes, jwt_refresh_expire_days, jwt_session_hours, jwt_refresh_reuse_grace_seconds, login_rate_limit_per_minute, auth_cache_seconds, abac_strict_permission_codes, and the bootstrap_admin_* settings (src/cluster_erp/config/settings.py:186-205, src/cluster_erp/config/settings.py:307-339). See the settings reference. Permission codes are seeded at every start-up (src/cluster_erp/server/app.py:634-948). The setting password_min_length is defined (src/cluster_erp/config/settings.py:327), but no code reads it at this commit (git grep password_min_length).
Tests¶
Found by file name and by a search for modules.auth imports in tests/, and by name in web-client/.
| Kind | File | Covers |
|---|---|---|
| pytest | tests/test_abac_evaluator.py |
operators, attributes, condition logic |
| pytest | tests/test_abac_enforcement.py |
check_abac and enforce_abac |
| pytest | tests/test_abac_policy_condition.py |
policy condition builder |
| pytest | tests/test_admin_bootstrap.py |
the first-boot administrator guard |
| pytest | tests/test_auth_cache_stamp.py |
cross-worker cache invalidation |
| pytest | tests/test_login_identifier.py |
sign-in identifier resolution |
| pytest | tests/test_login_budget_live.py |
the shared failure budget (live server) |
| pytest | tests/test_authz_conformance.py |
layered authorisation model |
| e2e | web-client/_e2e_auth_panels.mjs |
auth screens |
| e2e | web-client/_e2e_approvals.mjs, web-client/_e2e_approval_role.mjs, web-client/_e2e_approvals_integrity.mjs, web-client/_e2e_approvals_widget.mjs |
approval flow and inbox |
| e2e | web-client/_e2e_login_rate_limit.mjs, web-client/_e2e_session_remember.mjs |
sign-in limits and session length |
| e2e | web-client/_e2e_ui_states.mjs |
per-user UI state |
Terms introduced¶
| Term | Code identifier | Definition | Turkish term | Source |
|---|---|---|---|---|
| user | AuthUser |
A sign-in account of one person in one tenant. | Kullanıcı (webapp/i18n/tr.json key resource.user) |
src/cluster_erp/modules/auth/users/models.py:17 |
| user UI state | UserUiState |
One user's stored interface preference, keyed by a short name. | kullanıcı arayüz durumu | src/cluster_erp/modules/auth/ui_state/models.py:13 |
Related pages¶
- Modules index
- API reference for this module
- Identity, access, tenancy, privacy, and licensing
- Roles and permissions
Verified against commit 92f8051 on 2026-11-13.