Skip to content
This repository was archived by the owner on Aug 11, 2026. It is now read-only.
This repository was archived by the owner on Aug 11, 2026. It is now read-only.

feat(reporting): add module-contributed read models, incremental projections, freshness, and scheduled exports #753

Description

@ahliweb

Parent epic: #738
Depends on: #742, #745
Related foundation: existing reporting module

Context

The current reporting module provides management reporting, but scale and ERP-derived workloads should not depend on repeated live aggregation/heavy joins against transactional tables. Modules need a standard way to contribute read models or materialized projections with incremental cursors, rebuild/reconciliation, freshness state, and scheduled exports.

Objective

Extend reporting with module-contributed projection descriptors, event-driven/incremental updates, idempotent rebuild, freshness/staleness signals, source reconciliation, and scheduled export contracts.

Scope

  • Define a static projection descriptor containing:
    • stable projection key/version and owner module;
    • source event types/versions or source cursor contract;
    • tenant/global scope;
    • target read-model/materialized-view ownership;
    • incremental cursor/checkpoint strategy;
    • rebuild/reconcile handler;
    • freshness target and stale/error policy;
    • required permission/business scope;
    • drill-down/source-reference contract;
    • lifecycle/retention class.
  • Add projection registry validation and composed-registry integration.
  • Add incremental projection worker using feat(domain-events): add transactional event outbox, idempotent consumers, retries, ordering, and dead-letter handling #742 event consumers where applicable, shared jobs/locks/batching, idempotency, retry, pause/resume, and bounded transactions.
  • Add full or tenant-scoped rebuild with explicit safety guards, progress, cancellation, checkpoint/reset, and source reconciliation.
  • Support module-owned read tables and PostgreSQL materialized views where appropriate; reporting must not write source module tables.
  • Add freshness/status API and visible UI indicators for current, delayed, stale, rebuilding, and failed projections.
  • Add scheduled export descriptors/jobs with filters, business scope, format adapter, manifest/checksum, expiry, and secure download; reuse feat(data-exchange): add staged import, validation, preview, idempotent commit, export, and reconciliation #752 where feasible instead of duplicating export infrastructure.
  • Add drill-down links that resolve through source contracts and re-check current authorization.
  • Add metrics for source lag, projection lag, rebuild duration, rows processed, reconciliation mismatch, failure, and export outcome.
  • Migrate or wrap at least two representative existing reports to demonstrate the pattern without forcing all reporting to projections.

Security and integrity requirements

  • Projection/read-model data remains tenant-scoped with ENABLE + FORCE RLS and tenant-first indexes where applicable.
  • A projection is a derived read model, not an authorization source of truth. Every API/drill-down re-checks current RBAC/ABAC/business scope.
  • Projection failure or delay never rolls back or blocks the source transaction.
  • Rebuild is permission-gated, idempotent, audited, safe after interruption, and blocked against unsafe production-wide invocation unless explicitly authorized.
  • Sensitive fields are minimized/masked and cannot be added to a projection without descriptor/threat-model review.
  • Scheduled exports use least-privilege access, checksum, expiry, secure download, and lifecycle policy.

Out of scope

  • Generic BI/dashboard designer, arbitrary SQL supplied by tenants, or external data warehouse requirement.
  • Replacing all simple transactional queries with projections.
  • Treating projection freshness as strong transactional consistency.

Acceptance criteria

  • Modules can contribute validated projection descriptors without direct reporting-to-domain source imports/writes.
  • Incremental processing is idempotent and resumes correctly after duplicate events/worker restart.
  • Rebuild is bounded, resumable/cancelable, tenant-safe, and reconciles to source control totals.
  • Projection failure does not affect source transaction success.
  • Freshness/current-stale-rebuilding-failed status is exposed in API and UI with documented semantics.
  • Heavy representative dashboard queries use a read model/projection and no longer require repeated large live joins.
  • Authorization is re-evaluated at read/drill-down/export time; stale projection grants no stale privilege.
  • Scheduled export uses manifest/checksum/expiry and secure tenant-scoped download.
  • Cross-tenant RLS/ABAC, duplicate event, missed/replayed event, rebuild interruption, reconciliation mismatch, stale-state, and privacy tests pass.
  • Load evidence compares the representative live aggregation and projected read path.
  • OpenAPI/AsyncAPI, ERD/data dictionary, reporting/projection docs, freshness/SLO/runbook, privacy/threat model, admin/user guide, repository inventory, and changeset are updated.
  • bun run api:spec:check, bun run security:readiness, unit/PostgreSQL/worker/UI/E2E/performance tests, build, and bun run check pass.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:apiKontrak OpenAPI/RESTarea:architectureStruktur repo, module contract, registryarea:databaseSchema, migration, pooling, RLSarea:frontendAstro SSR, islands, UI clientpriority:p1Prioritas tinggi - core domaintype:featureFitur baru sesuai doc 06

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions