Skip to content

fix(rbac,payments,search,rate-limit): close Mai-Fura issues 833, 824, 814, 808#1058

Open
Mai-Fura wants to merge 1 commit into
rinafcode:mainfrom
Mai-Fura:fix/mai-fura-issues-833-824-814-808
Open

fix(rbac,payments,search,rate-limit): close Mai-Fura issues 833, 824, 814, 808#1058
Mai-Fura wants to merge 1 commit into
rinafcode:mainfrom
Mai-Fura:fix/mai-fura-issues-833-824-814-808

Conversation

@Mai-Fura

@Mai-Fura Mai-Fura commented Jul 23, 2026

Copy link
Copy Markdown

Closes #833
Closes #824
Closes #814
Closes #808

#833 — Audit log entries for RBAC role assignment and revocation

  • New RBAC_* entries in AuditAction (RBAC_ROLE_ASSIGNED / REVOKED / CREATED / UPDATED / DELETED, RBAC_PERMISSION_GRANTED / REVOKED / CREATED / UPDATED / DELETED).
  • RbacModule imports AuditLogModule; RolesService and PermissionsService inject AuditLogService and write a SECURITY-category audit entry on every create/update/delete, plus explicit grant/revoke deltas computed from updateRole permissionId diffs.
  • The new mappings are populated in sensitive-operations.service.ts so the exhaustive Record<AuditAction, AuditCategory> type-checks.

#824 — Idempotency keys for payment creation endpoints

  • IdempotencyInterceptor registered globally as APP_INTERCEPTOR in AppModule, so any @Idempotent() decorator resolves.
  • @Idempotent() applied on:
    • POST /payment-methods
    • POST /subscriptions/:subscriptionId/upgrade
    • POST /subscriptions/:subscriptionId/downgrade
    • POST /payments/payouts/admin/process
  • IdempotencyModule defensively imported in PaymentsModule and PayoutsModule.
  • Duplicate requests with the same Idempotency-Key within the configured TTL return the cached 2xx response (no DB record, no provider charge).

#808 — Rate limiting is on by default

  • ENABLE_RATE_LIMITING replaced with DISABLE_RATE_LIMITING (default false). Operators must explicitly opt out.
  • A WARN log is emitted from OnApplicationBootstrap when DISABLE_RATE_LIMITING=true.
  • getDisabledModules() correctly reports RateLimitingModule when opted out.
  • ENABLE_RATE_LIMITING=false|0 honored as a transient back-compat alias.

#814 — Course search full-text index

  • New migration 1783000000003-add-course-full-text-search.ts adds a STORED generated tsvector column on course and a GIN index, fully reversible in down().
  • SearchService uses plainto_tsquery against the GIN-indexed column, ranks by ts_rank, falls back to ILIKE, and prefers Elasticsearch when available.
  • Course entity mirrors the column via @Index(IDX_course_search_vector) so synchronize parity holds.

Validation

  • pnpm run typecheck: pass
  • npx jest --testPathPattern=src/rbac|src/search: 16/16 pass (rbac audits + search service)
  • pnpm run lint: pass (one pre-existing auth.service.ts unused warning; no new errors)

Diff stats: 19 files, +1112 / −170.

… 814, 808

Closes rinafcode#833 rinafcode#824 rinafcode#814 rinafcode#808

rinafcode#833 Audit log entries for RBAC role assignment and revocation
- Add RBAC_ROLE_ASSIGNED, RBAC_ROLE_REVOKED, RBAC_PERMISSION_GRANTED,
  RBAC_PERMISSION_REVOKED, plus ROLE_CREATED/UPDATED/DELETED and
  PERMISSION_CREATED/UPDATED/DELETED enum values.
- RbacModule imports AuditLogModule; RolesService and PermissionsService
  inject AuditLogService and write SECURITY-category audit entries on
  every mutation, including explicit grant/revoke deltas computed from
  updateRole permissionId diffs.
- Fill the new RBAC_* mappings in sensitive-operations.service.ts so the
  exhaustive Record<AuditAction, AuditCategory> type-checks.

rinafcode#824 Idempotency keys for payment creation endpoints
- Register IdempotencyInterceptor globally as APP_INTERCEPTOR in
  AppModule so every @idempotent() decorator resolves.
- Apply @idempotent() to POST /payment-methods,
  /subscriptions/:id/upgrade, /subscriptions/:id/downgrade, and
  /payments/payouts/admin/process.
- Defensive import of IdempotencyModule in PaymentsModule and
  PayoutsModule so the IdempotencyService is always resolvable.

rinafcode#808 Rate limiting is on by default
- Flip ENABLE_RATE_LIMITING to DISABLE_RATE_LIMITING (default false).
  Operators must opt out; a WARN log is emitted on
  OnApplicationBootstrap when DISABLE_RATE_LIMITING=true.
- getDisabledModules now reports RateLimitingModule when opted out.
- ENABLE_RATE_LIMITING=false|0 is honored as a back-compat alias.

rinafcode#814 Course search full-text index
- New migration 1783000000003-add-course-full-text-search.ts adds a
  STORED generated tsvector column on course and a GIN index, with a
  fully reversible down().
- SearchService uses plainto_tsquery with the GIN index, falls back to
  ILIKE, ranks by ts_rank, and prefers Elasticsearch when available.
- Course entity mirrors the column via @Index so synchronize parity
  holds and the migration is self-defending.

Tests: 16/16 unit tests pass (rbac + search).
Typecheck: pass.
Lint: pass (one pre-existing auth.service warning; no new errors).
@drips-wave

drips-wave Bot commented Jul 23, 2026

Copy link
Copy Markdown

@Mai-Fura Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

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

Labels

None yet

Projects

None yet

1 participant