Skip to content

feat(compliance): compliance reporting engine (SAT/UIF) + alert SLA p… - #320

Merged
ericmt-98 merged 2 commits into
Micopay:mainfrom
ShantelPeters:feat/compliance-reporting-5a
Jul 23, 2026
Merged

feat(compliance): compliance reporting engine (SAT/UIF) + alert SLA p…#320
ericmt-98 merged 2 commits into
Micopay:mainfrom
ShantelPeters:feat/compliance-reporting-5a

Conversation

@ShantelPeters

Copy link
Copy Markdown
Contributor

…ipeline

Closes #317

  • Adds monthly aggregation (>=210 UMA threshold) & zero-report generation (compliance.service.ts)
  • Adds compliance_alerts table with 24h SLA deadline tracking and compliance_filings table (migration 20260721130000_compliance_reporting)
  • Adds append-only triggers on platform_risk_events, compliance_alerts, and compliance_filings
  • Exposes query/admin endpoints (/admin/compliance/alerts, /admin/compliance/filings, /admin/compliance/filings/trigger)
  • Adds 10-year retention policy documentation (RETENTION_POLICY.md)
  • Adds unit/integration test suite (compliance.test.ts)

CLOSES #317

@ericmt-98 ericmt-98 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this — the append-only trigger design, the 24h-SLA alert tracking, the zero-report path, and the injected test suite are all the right shape for what #317 needs. Two blockers and a couple of cleanups before this can merge:

🔴 Blocker 1 — micopay/backend/src/config.ts is truncated to a broken 10-line fragment

The committed config.ts on this branch is only:

  // Compliance / SAT reporting
  umaValMxn: parseFloat(process.env.UMA_VAL_MXN || '113.15'),
  satFilingThresholdUma: parseFloat(process.env.SAT_FILING_THRESHOLD_UMA || '210'),
  // LFPIORPI aviso (reporting) thresholds
  umaDailyMxn: ...

The entire module is gone — the imports, loadEnv, parseAllowedOrigins, the KycOperationType/KycThresholdTier types, parseKycOperationThresholds, the whole config object (port, databaseUrl, stellar, jwt, rate limits, the KYC gate config…), validateConfig, and getCorsOptions. The backend won't compile or boot with this. It looks like a merge/rebase conflict against the recent threshold-config commit (fbc8c7b) got resolved by dropping the file's contents.

Fix: rebase onto latest main and re-apply only your compliance additions (umaValMxn/satFilingThresholdUma) on top of the full file. Note main already has umaDailyMxn (117.31) and kycAvisoThresholdUma (210) from fbc8c7b — reuse those instead of adding parallel copies (see the two minor notes below).

CI would normally have caught this, but it doesn't run on fork branches — so please run cd micopay/backend && npx tsc --noEmit locally to confirm before pushing.

🔴 Blocker 2 — compliance_filings.status contradicts the append-only trigger

The table defines status VARCHAR(20) DEFAULT 'pending_submission', which implies status later moves to submitted. But enforce_append_only_compliance_filings blocks all UPDATEs on the table, so status can never change. Either the filing status needs to be mutable (then it can't live on an append-only table — split the mutable status into a separate table, or track submission as a new appended row), or it's genuinely immutable (then drop the status column). As written the submission workflow is unreachable.

Minor

  • Stale UMA value: umaValMxn defaults to 113.15 — that's the 2025 UMA. The 2026 value is 117.31 (already in main as umaDailyMxn). Please consolidate onto the single existing umaDailyMxn rather than introducing a second, stale UMA constant.
  • Duplicate threshold: satFilingThresholdUma duplicates the existing kycAvisoThresholdUma (both 210 UMA). Reuse the existing one.

The reporting logic and migration are otherwise solid — this is mostly reconciling with what already landed on main. Thanks again!

@ericmt-98

Copy link
Copy Markdown
Collaborator

Hi @ShantelPeters — just checking in, no pressure on timing. The main thing here is the config.ts on the branch is a 10-line fragment (the rest of the module got dropped in a conflict resolution), so it won't build as-is. The fix is straightforward: rebase onto latest main and re-apply just your two compliance additions on top of the full file — main already has umaDailyMxn (117.31) and kycAvisoThresholdUma (210), so you can reuse those. The reporting logic and migration themselves are in good shape. Happy to help if the rebase gets tangled — just say the word.

…ipeline

Closes Micopay#317

- Adds monthly aggregation (>=210 UMA threshold) & zero-report generation (compliance.service.ts)
- Adds compliance_alerts table with 24h SLA deadline tracking and compliance_filings table (migration 20260721130000_compliance_reporting)
- Adds append-only triggers on platform_risk_events, compliance_alerts, and compliance_filings
- Exposes query/admin endpoints (/admin/compliance/alerts, /admin/compliance/filings, /admin/compliance/filings/trigger)
- Adds 10-year retention policy documentation (RETENTION_POLICY.md)
- Adds unit/integration test suite (compliance.test.ts)
@ShantelPeters
ShantelPeters force-pushed the feat/compliance-reporting-5a branch from 1c92dfe to 48f4c51 Compare July 23, 2026 00:13
@ericmt-98

Copy link
Copy Markdown
Collaborator

Merging — thanks for the quick turnaround, @ShantelPeters. Both blockers are properly resolved and I built + ran it locally (CI doesn't run on fork branches):

  • config.ts fixed — reconciled cleanly against main; you reused the existing umaDailyMxn (117.31) and kycAvisoThresholdUma (210) instead of re-adding parallel constants. The service computes the threshold as umaDailyMxn * kycAvisoThresholdUma = $24,635.10. ✅
  • status/append-only contradiction fixed — dropping the mutable status column makes compliance_filings genuinely append-only, consistent with the trigger. ✅
  • cd micopay/backend && npx tsc --noEmit ✅ · npm run test:compliance (5 tests incl. append-only enforcement) ✅ · no regression in kyc-gate / kyc-didit / abuse ✅
  • Nice touch mirroring the append-only guard into the in-memory store (schema.ts) so the enforcement test actually validates in CI/local without Postgres. And I confirmed no production code path mutates platform_risk_events / compliance_alerts / compliance_filings, so the triggers are safe to apply to the live DB on boot-migrate.

One hardening note for later (not a blocker for single-instance testnet): the hourly checkAndRunComplianceJob is idempotent via the if (!existing) check, but compliance_filings has no UNIQUE (period_start, filing_type) constraint — so under horizontal scaling two instances could race and both insert a filing for the same period. Same leader-election caveat as the existing refund sweep; worth a UNIQUE constraint before we scale out. Thanks again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[5a] Compliance Reporting Engine — SAT/UIF Monthly Aggregation

2 participants