This page describes four files of the analytics module in src/cluster_erp/modules/analytics/: reports.py (documents built from captured results), summaries.py (pre-aggregated summary cells), profiling.py (data profiles and the shared column allow-list), and cross.py (alignment of two fact sets on a period axis).
Scope and source¶
- Defined in:
ReportService(src/cluster_erp/modules/analytics/reports.py:73), the summary functionsload_states,refresh, andplan(src/cluster_erp/modules/analytics/summaries.py:345-500),profile_targetsandProfiler(src/cluster_erp/modules/analytics/profiling.py:118-142), and the pure functions ofcross.py(src/cluster_erp/modules/analytics/cross.py:28-157). - Tables:
analytics_reports,analytics_report_items,analytics_summary_cells,analytics_summary_state(src/cluster_erp/modules/analytics/models.py:66-148). - Routes:
/analysis/reports(9 routes),/analysis/summariesand/analysis/summaries/refresh,/analysis/profile/{fact_key},/analysis/cross/compare/{fact_a}, and/analysis/cross/correlate/{fact_a}(src/cluster_erp/modules/analytics/routes.py:56-78,src/cluster_erp/modules/analytics/routes.py:686-785,src/cluster_erp/modules/analytics/routes.py:1071-1237).
Reports¶
A report is a named document of captured analysis results. A report item stores the kind, fact, and parameters, and also the result snapshot with its capture time, so a report never changes when the data does (src/cluster_erp/modules/analytics/reports.py:1-17).
| Rule | Detail | Source |
|---|---|---|
| Visibility | owner plus organisation-wide is_shared; editing is owner-only |
src/cluster_erp/modules/analytics/reports.py:10-12 |
| Access answers | a foreign private report answers not found; a shared report edited by a non-owner answers forbidden | src/cluster_erp/modules/analytics/reports.py:12-14 |
| Content | snapshots contain semantic keys and computed numbers only | src/cluster_erp/modules/analytics/reports.py:15-17 |
| Items | add, update, move, and remove items | src/cluster_erp/modules/analytics/reports.py:222-362 |
| Removal | a report is deactivated with a reason | src/cluster_erp/modules/analytics/reports.py:198-220 |
Summary cells¶
The summary cells keep, per fact set and per date axis, one row per day and combination of summary dimensions, with the row count and the sum and non-null count of every decomposable measure. A report that fits the cells is answered from them, and the current day is always read live (src/cluster_erp/modules/analytics/summaries.py:1-17).
flowchart LR
F["fact table rows"] -->|refresh by updated_at watermark| C["AnalyticsSummaryCell per day and dims"]
F -->|full rebuild| C
C --> P{"summaries.plan"}
T["today rows, live"] --> P
P -->|fits| S["answer source summary"]
P -->|Ineligible with reason| L["answer source live"]In prose:
- Cells are keyed by every text and boolean dimension and by the reference dimensions that the contributing module marked
rollup(src/cluster_erp/modules/analytics/summaries.py:89-99). - A measure is served from cells only when its aggregation decomposes:
count,sum, andavgas sum over count.count_distinct,median,min, andmaxstay live (src/cluster_erp/modules/analytics/summaries.py:21-23). - A query that uses a dimension outside the summary set, a second date axis, or an ordering operator on text runs live; the result states its
sourceand the reason (src/cluster_erp/modules/analytics/summaries.py:24-26,src/cluster_erp/modules/analytics/summaries.py:399-426,src/cluster_erp/modules/analytics/service.py:157-168). - Cells exclude the rows the live filter excludes; a deactivation changes
updated_at, so its day is recomputed (src/cluster_erp/modules/analytics/summaries.py:27-28). - The refresh is incremental by
updated_ateveryanalytics_summary_refresh_seconds(default 60); a full rebuild runs everyanalytics_summary_rebuild_minutes(default 60). A fact set is served from cells only after its first refresh (src/cluster_erp/modules/analytics/summaries.py:29-40,src/cluster_erp/config/settings.py:528-531,src/cluster_erp/server/app.py:461-470). GET /analysis/summariesshows the state per fact and axis;POST /analysis/summaries/refreshruns a refresh or a rebuild on demand (src/cluster_erp/modules/analytics/routes.py:1207-1237,src/cluster_erp/modules/analytics/service.py:170-198).
The docstring states that cells are derived data, so deleting and rewriting a cell is not the deletion of a record (src/cluster_erp/modules/analytics/summaries.py:18-20).
Profiling¶
A profile covers table-level and column-level metrics by default; dependency discovery runs only on demand and on a sample (src/cluster_erp/modules/analytics/profiling.py:1-14).
profile_targetsturns a fact's declared dimensions and measure columns into the list of profilable columns. It is the shared allow-list used by statistics, inference, series, and recipes (src/cluster_erp/modules/analytics/profiling.py:118-140).- Deactivated rows are excluded through
live_scope(src/cluster_erp/modules/analytics/profiling.py:55-68). - Quantiles use
percentile_disc; there is noround()and no float cast in the generated SQL (src/cluster_erp/modules/analytics/profiling.py:24-27). - A relation larger than
analytics_profile_exact_max_rows(default 200000) is profiled on a sample ofanalytics_profile_sample_rows(default 50000), and the profile says so (src/cluster_erp/modules/analytics/profiling.py:29-33,src/cluster_erp/modules/analytics/profiling.py:166,src/cluster_erp/config/settings.py:485-486). - For a monetary column whose rows span several currencies, the numeric and ordered metrics are not computed (
src/cluster_erp/modules/analytics/profiling.py:216-250).
Cross-fact comparison¶
cross.py aligns two fact sets on a shared period axis built by the same series engine (src/cluster_erp/modules/analytics/cross.py:1-15):
- The join is inner on periods defined on both sides; each side's exclusive periods are counted, not dropped (
src/cluster_erp/modules/analytics/cross.py:41-80). - An optional lag shifts side B by whole periods.
- A categorical side is derived from counts as presence or share, and the derivation is reported (
src/cluster_erp/modules/analytics/cross.py:82-115).
Both fact sets resolve through the caller's permission-filtered catalogue; an unreadable side makes the whole question unknown (src/cluster_erp/modules/analytics/service.py:535-563).
Constraints and validation¶
- Report items and saved models never store physical names (
src/cluster_erp/modules/analytics/reports.py:15-17). - The summary refresh is a background loop on the server; a deployment with the refresh switched off answers everything live (
src/cluster_erp/modules/analytics/summaries.py:38-39).
Terms introduced¶
| Term | Code identifier | Definition | Turkish term | Source |
|---|---|---|---|---|
| summary cell | AnalyticsSummaryCell |
One pre-aggregated row per fact, date axis, day, and dimension combination. | Özet hücresi | src/cluster_erp/modules/analytics/models.py:112 |
| report item | AnalyticsReportItem |
A captured analysis inside a report, with its result snapshot. | Rapor kalemi | src/cluster_erp/modules/analytics/models.py:86 |
| profile target | profile_targets |
A declared column that profiling and statistics may read. | Profil hedefi | src/cluster_erp/modules/analytics/profiling.py:118 |
Related pages¶
Verified against commit 92f8051 on 2026-11-13.