Factorizer/Cluster ERP WikiCluster ERP Türkçe
Home / Business modules

Module

Records module (records)

Module page for records, the record lifecycle with the deactivation reason catalogue, generic reactivation and passive lists, and the retention window and purge.

The records module in src/cluster_erp/modules/records/ owns the lifecycle of records under the rule that nothing is deleted outright. It keeps the catalogue of deactivation reasons, offers generic endpoints to list deactivated records of any entity and to reactivate them, and keeps the retention window after which the daily purge removes deactivated rows for good (src/cluster_erp/modules/records/module.py:15-22). The deactivation mechanism itself is described on soft delete and deactivation.

At a glance

Item Value Source
Package src/cluster_erp/modules/records/ folder
Module class Module src/cluster_erp/modules/records/module.py:15
name / version records / 0.1.0 src/cluster_erp/modules/records/module.py:24-30
API prefix /api/v1/records (ModuleBase.api_prefix) src/cluster_erp/core/module_base.py:37-38, src/cluster_erp/modules/records/module.py:39-52
Sub-modules 2: deactivation_reasons, retention; plus lifecycle_routes.py and resolver.py folder listing
Tables 3: core_deactivation_reasons, core_retention_config, core_retention_runs __tablename__ in the two models.py files
Entities in metadata 1 key in entities src/cluster_erp/modules/records/module.py:73-75
Routes 10 route decorators in the package grep for @...router.get/post/put/patch/delete
Actions 0 ActionMeta entries grep "ActionMeta(" in the package
Migrations 7 files files in migrations/versions/ whose text contains one of the three table names
Contracts consumes 0, produces 1 see the section "Events and queries"
Web app presence No sidebar section; surfaced from the web Settings screen src/cluster_erp/modules/records/module.py:21-22, src/cluster_erp/modules/records/module.py:72
Desktop presence generic widgets only src/cluster_erp/desktop/modules/ has no records folder

What the module does

  • Keeps the deactivation reasons an administrator can choose when a record is removed from use (src/cluster_erp/modules/records/deactivation_reasons/models.py:9-32).
  • Lists the deactivated records of any deactivatable entity, resolves labels of records that may be inactive, and reactivates a record (src/cluster_erp/modules/records/lifecycle_routes.py:1-10).
  • Keeps the retention window in years and the evidence rows of each retention pass (src/cluster_erp/modules/records/retention/models.py:14-49).
  • Provides purge_expired, the function that physically deletes deactivated rows and change history older than the window (src/cluster_erp/modules/records/retention/purge.py:1-7).

Sub-modules

Sub-module Purpose Main entities Router Source
deactivation_reasons Reason catalogue DeactivationReason /deactivation-reasons src/cluster_erp/modules/records/deactivation_reasons/routes.py:21
retention Retention window, evidence rows, purge RetentionConfig, RetentionRun /retention src/cluster_erp/modules/records/retention/routes.py:14
lifecycle_routes.py Passive lists, labels, reactivation any deactivatable entity /{module}/{entity}/... src/cluster_erp/modules/records/lifecycle_routes.py:32

Data model

Entity Table Key fields Notes Source
DeactivationReason core_deactivation_reasons code, label_en, label_tr, requires_note, sort_order, is_active code unique among live rows; deactivated records point to it through their deactivation_reason column src/cluster_erp/modules/records/deactivation_reasons/models.py:9-32
RetentionConfig core_retention_config retention_years single row, default 10 src/cluster_erp/modules/records/retention/models.py:19-30
RetentionRun core_retention_runs id (integer), ran_at, kind, summary evidence of each pass that removed data; plain Base without audit or soft-delete columns src/cluster_erp/modules/records/retention/models.py:33-49

Record lifecycle

flowchart TD
 L["live record"] -->|DELETE with reason| D["deleted_at, deleted_by, deactivation_reason set"]
 R["DeactivationReason catalogue"] --> D
 D --> H["core_change_history row"]
 D --> P["GET /records/module/entity/inactive"]
 P -->|POST .../record_id/activate| L
 D -->|older than retention_years| X["purge_expired: physical delete"]
 X --> E["RetentionRun evidence row"]

In prose:

  1. A delete route of any module sets deleted_at. The central change-history hook stamps deleted_by and the reason from the request context, so no module threads the reason itself (src/cluster_erp/core/change_history.py:245-259). The change is written to the change history; see change history.
  2. GET /records/{module}/{entity}/inactive lists the deactivated rows of an entity, newest first, after checking {entity}.read and the app entitlement of the module (src/cluster_erp/modules/records/lifecycle_routes.py:114-172).
  3. POST /records/{module}/{entity}/{record_id}/activate checks {entity}.delete, clears deleted_at and deactivation_reason, and emits RecordActivated (src/cluster_erp/modules/records/lifecycle_routes.py:224-269).
  4. Once a day the server runs the retention pass. It calls purge_expired with the configured window for every database the node serves, and emits RetentionSweep so modules drop their own time-window rows (src/cluster_erp/server/app.py:227-260, src/cluster_erp/server/app.py:404-460).
  5. purge_expired deletes the files of expired attachments first, then every table with a deleted_at column, each in its own savepoint, then change history and the legacy audit_log older than the window. A foreign-key conflict on one table is logged and skipped (src/cluster_erp/modules/records/retention/purge.py:33-176).
  6. Each pass that removed data writes a RetentionRun row; a failure to write it does not block the purge (src/cluster_erp/modules/records/retention/services.py:20-32).

Screens and metadata

The module has no sidebar group; the code states that it is surfaced from the web Settings screen (src/cluster_erp/modules/records/module.py:15-22, src/cluster_erp/modules/records/module.py:72). Its one entity is deactivation_reason (src/cluster_erp/modules/records/module.py:73-75). The web client offers the reason list when a record is deactivated (webapp/js/a11y-ui.js:156). Passive lists and reactivation in the web app are described on records, documents, viewer, and share.

Status and actions

The module declares no ActionMeta. Its state is the deleted_at column of other modules' records.

Business rules

  • Only entities whose metadata declares a delete endpoint are deactivatable. resolver.py builds the map from module and entity to model once at start, with hand-verified overrides for irregular table names, and logs every entity it cannot resolve as an error (src/cluster_erp/modules/records/resolver.py:1-19, src/cluster_erp/modules/records/resolver.py:35-40).
  • The retention window is clamped between 6 and 250 years (src/cluster_erp/modules/records/retention/models.py:14-16, src/cluster_erp/modules/records/retention/services.py:49-54).
  • The purge skips core_change_history, deleted_records, alembic_version, and core_retention_config in the generic sweep (src/cluster_erp/modules/records/retention/purge.py:23-30).
  • A reason marked requires_note asks for a free-text note in the web client; a server-side check of the reason code against the catalogue was not found outside the web client (webapp/js/a11y-ui.js:156).
  • Deleting a reason sets deleted_at (src/cluster_erp/modules/records/deactivation_reasons/services.py:73-79).

Events and queries

The module consumes no contract and produces 1, counted as on the fleet module page.

Direction Contract class Handler or emitter Source
emits RecordActivated activate route src/cluster_erp/modules/records/lifecycle_routes.py:257-268

RetentionSweep is emitted by the server with source_module="records", not by the package itself (src/cluster_erp/server/app.py:240). The full list is on the contracts reference.

Permissions

Permission key Used by Source
deactivation_reason.read, .create, .update, .delete reason catalogue src/cluster_erp/modules/records/deactivation_reasons/routes.py:24-82
retention_config.read, .update retention window src/cluster_erp/modules/records/retention/routes.py:17-35
{entity}.read passive lists and labels src/cluster_erp/modules/records/lifecycle_routes.py:126, src/cluster_erp/modules/records/lifecycle_routes.py:191
{entity}.delete reactivation src/cluster_erp/modules/records/lifecycle_routes.py:234

Privacy, retention, and history

The module has no privacy_handlers.py. It owns the retention window and the purge described above. The scheduling of the daily pass is on scheduled jobs and retention.

Analytics facts

This module has no analytics_facts.py.

Settings and reference data

  • GET and PUT /records/retention/ read and set the window; a missing row is created with the default of 10 years (src/cluster_erp/modules/records/retention/routes.py:17-35, src/cluster_erp/modules/records/retention/services.py:39-47).
  • The deactivation reasons are the module's reference data. A seed of reasons was not found in the package.

Tests

Found by a grep for /records/ in web-client/_e2e_*.mjs and for modules.records, /records/, or retention in tests/*.py.

Kind File Covers
e2e web-client/_e2e_deactivate_reason.mjs, web-client/_e2e_deactivate_ui.mjs deactivation with a reason
e2e web-client/_e2e_lifecycle.mjs passive lists and reactivation
e2e web-client/_e2e_records_entitlement.mjs app entitlement on lifecycle routes
e2e web-client/_e2e_retention.mjs retention window
pytest tests/test_control_retention.py, tests/test_data_map_package1.py, tests/test_tenancy.py files that mention records or retention

Discrepancies

Terms introduced

Term Code identifier Definition Turkish term Source
deactivation reason DeactivationReason A catalogue entry that says why a record was removed from use. devre dışı bırakma nedeni src/cluster_erp/modules/records/deactivation_reasons/models.py:9
retention window retention_years The years a deactivated record is kept before the purge removes it. Saklama süresi src/cluster_erp/modules/records/retention/models.py:19-30
passive record list_inactive A record with deleted_at set, listed for review and reactivation. Pasif kayıt src/cluster_erp/modules/records/lifecycle_routes.py:114-115

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

Verified against commit 92f8051 · 2026-11-13