Skip to content

ready for merge#351

Merged
OlufunbiIK merged 1 commit intoOlufunbiIK:mainfrom
mimijuwonlo-commits:godsmiracle
Mar 29, 2026
Merged

ready for merge#351
OlufunbiIK merged 1 commit intoOlufunbiIK:mainfrom
mimijuwonlo-commits:godsmiracle

Conversation

@mimijuwonlo-commits
Copy link
Copy Markdown
Contributor

@mimijuwonlo-commits mimijuwonlo-commits commented Mar 29, 2026

close #322
close #323
close #324
close #325

Summary by CodeRabbit

  • New Features

    • Enhanced admin security logging for better auditability.
  • Refactor

    • Simplified API route paths by removing /api prefix from subscription, payout, referral, and waveform endpoints.
    • Standardized user identification handling across authentication and admin systems for consistency.
    • Extended module structure to support new admin and verification capabilities.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 29, 2026

@mimijuwonlo-commits is attempting to deploy a commit to the olufunbiik's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 29, 2026

📝 Walkthrough

Walkthrough

The PR normalizes authenticated request context across guards and controllers by introducing CurrentUserData type for decorator output, switching userId field extraction across multiple components, updating route prefixes from hardcoded api/xyz to xyz for consistent global prefix handling, making RolesGuard asynchronous with database lookups, and mounting AdminModule and VerificationModule in the application.

Changes

Cohort / File(s) Summary
Admin Authorization
backend/src/admin/admin.controller.ts, backend/src/admin/guards/admin-role.guard.ts
Updated admin controller to use CurrentUserData and pass admin.userId to service methods. Enhanced admin-role guard with per-request logging on denial paths and narrowed user identifier extraction from user.id to user.userId.
Auth Guards
backend/src/auth/guards/roles.guard.ts
Changed RolesGuard.canActivate from synchronous to async; now injects Repository<User> and performs database lookup by userId, returning false if user not found before checking role membership.
Route Prefix Normalization
backend/src/artiste-payout/payouts.controller.ts, backend/src/social-sharing/referral.controller.ts, backend/src/subscription-tiers/subscriptions.controller.ts, backend/src/waveform/waveform.controller.ts
Removed hardcoded /api segment from controller route prefixes (api/payoutspayouts, api/referralsreferrals, api/subscriptionssubscriptions, api/waveformwaveform) to align with global prefix strategy.
CurrentUser Decorator Adoption
backend/src/artists/artists.controller.ts, backend/src/recommendations/recommendations.controller.ts, backend/src/subscription-tiers/subscriptions.controller.ts, backend/src/verification/verification.controller.ts
Replaced @Request() req: any parameter extraction with @CurrentUser("userId") userId: string across multiple handlers; updated type from User to CurrentUserData in verification controller.
Module Mounting
backend/src/app.module.ts
Added AdminModule and VerificationModule imports to AppModule to enable admin and verification routes in the live application.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • PR #58: Modifies RolesGuard with async role checking and repository-based user lookup, directly related to auth guard changes in this PR.
  • PR #128: Updates admin module files (admin.controller.ts, admin.service.ts, admin-role.guard.ts) with admin permission logic that this PR refactors to use userId field.
  • PR #29: Introduces user-scoped endpoints in artists.controller.ts that this PR refactors to adopt the @CurrentUser decorator pattern.

Poem

🐰 A rabbit hops through guards and routes with glee,
CurrentUser flows so clear and decree,
Admin and verification now take their place,
Normalized context runs at a steady pace!
No more req.user, just clean userId—
The auth dance is finally spry! 🎭✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'ready for merge' is vague and does not describe the actual changes. It provides no meaningful information about what was modified. Replace with a descriptive title summarizing the primary changes, such as 'Normalize auth context, standardize routes, and mount admin/verification modules' or similar.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed All four linked issues (#322, #323, #324, #325) objectives are substantially met: authenticated context normalized with userId, route prefixes standardized by removing hardcoded /api, admin module mounted with guard reconciliation, and verification module mounted.
Out of Scope Changes check ✅ Passed All changes directly address the linked issues: auth context normalization, route standardization, admin/verification module mounting, and guard updates. No unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
backend/src/verification/verification.controller.ts (1)

67-74: ⚠️ Potential issue | 🔴 Critical

Use ForbiddenException instead of generic Error for access control.

Throwing a generic Error returns HTTP 500 instead of 403. The global exception filter only remaps HttpException subclasses; plain Error instances default to INTERNAL_SERVER_ERROR status code.

Suggested fix
 import {
   Controller,
   Get,
   Post,
   Patch,
   Delete,
   Body,
   Param,
   Query,
   UseGuards,
   UseInterceptors,
   UploadedFiles,
   ParseUUIDPipe,
   HttpCode,
   HttpStatus,
+  ForbiddenException,
 } from '@nestjs/common';
@@
-    if (!user.isArtist) {
-      throw new Error('Only artists can request verification');
-    }
+    if (!user.isArtist) {
+      throw new ForbiddenException('Only artists can request verification');
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/verification/verification.controller.ts` around lines 67 - 74, In
createVerificationRequest change the thrown generic Error to Nest's
ForbiddenException so access denial returns HTTP 403: replace the throw new
Error('Only artists can request verification') in the createVerificationRequest
method with throw new ForbiddenException('Only artists can request
verification') (import ForbiddenException from `@nestjs/common` if not already
imported).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/src/admin/guards/admin-role.guard.ts`:
- Around line 47-49: Remove logging of raw user.userId in the AdminRoleGuard
logger.warn calls and replace with a privacy-safe identifier: either use the
existing request/correlation id from the execution context (if available) or log
a redacted/hashed form of the principal (e.g., SHA-256 or truncated HMAC of
user.userId) so the original stable identifier is not persisted; update both the
warn at the `Denied admin access: no admin role for userId=${user.userId}` site
and the similar warn/error calls around the other occurrence (lines referenced
in the review) to include the correlation id or the hashed/redacted user id
instead of user.userId, and ensure the hashing uses a constant salt/config so
the resulting token can be correlated for troubleshooting without exposing the
raw value.

In `@backend/src/auth/guards/roles.guard.ts`:
- Around line 9-12: RolesGuard is injectable and injects User repository but
isn't provided by any module, causing runtime resolution failures where
controllers use `@UseGuards`(RolesGuard); add RolesGuard to the AuthModule
providers and exports (alongside TypeOrmModule.forFeature([User]) and existing
providers like AuthService and JwtAuthGuard) so it can be injected, then ensure
modules using `@UseGuards`(RolesGuard) import AuthModule (or export RolesGuard
from a shared guards module) so RolesGuard can be resolved at runtime.

---

Outside diff comments:
In `@backend/src/verification/verification.controller.ts`:
- Around line 67-74: In createVerificationRequest change the thrown generic
Error to Nest's ForbiddenException so access denial returns HTTP 403: replace
the throw new Error('Only artists can request verification') in the
createVerificationRequest method with throw new ForbiddenException('Only artists
can request verification') (import ForbiddenException from `@nestjs/common` if not
already imported).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a66ef2b2-113c-4f8c-a9f5-7f10194e71f3

📥 Commits

Reviewing files that changed from the base of the PR and between aae34c4 and b04a218.

📒 Files selected for processing (11)
  • backend/src/admin/admin.controller.ts
  • backend/src/admin/guards/admin-role.guard.ts
  • backend/src/app.module.ts
  • backend/src/artiste-payout/payouts.controller.ts
  • backend/src/artists/artists.controller.ts
  • backend/src/auth/guards/roles.guard.ts
  • backend/src/recommendations/recommendations.controller.ts
  • backend/src/social-sharing/referral.controller.ts
  • backend/src/subscription-tiers/subscriptions.controller.ts
  • backend/src/verification/verification.controller.ts
  • backend/src/waveform/waveform.controller.ts

Comment on lines +47 to +49
logger.warn(
`Denied admin access: no admin role for userId=${user.userId}`,
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid logging raw userId values on authorization failures.

These warning paths persist stable user identifiers in auth logs. That is unnecessary for denial auditing and creates a privacy/compliance risk. Prefer a request/correlation ID, or redact/hash the principal before logging.

🛠️ Minimal fix
-      logger.warn(
-        `Denied admin access: no admin role for userId=${user.userId}`,
-      );
+      logger.warn(
+        'Denied admin access: no admin role for authenticated principal',
+      );
...
-      logger.warn(
-        `Denied admin access: missing permissions for userId=${user.userId} required=${requiredPermissions.join(',')}`,
-      );
+      logger.warn(
+        `Denied admin access: missing permissions required=${requiredPermissions.join(',')}`,
+      );

Also applies to: 58-60

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/admin/guards/admin-role.guard.ts` around lines 47 - 49, Remove
logging of raw user.userId in the AdminRoleGuard logger.warn calls and replace
with a privacy-safe identifier: either use the existing request/correlation id
from the execution context (if available) or log a redacted/hashed form of the
principal (e.g., SHA-256 or truncated HMAC of user.userId) so the original
stable identifier is not persisted; update both the warn at the `Denied admin
access: no admin role for userId=${user.userId}` site and the similar warn/error
calls around the other occurrence (lines referenced in the review) to include
the correlation id or the hashed/redacted user id instead of user.userId, and
ensure the hashing uses a constant salt/config so the resulting token can be
correlated for troubleshooting without exposing the raw value.

Comment on lines +9 to +12
constructor(
private reflector: Reflector,
@InjectRepository(User) private readonly userRepository: Repository<User>,
) {}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "RolesGuard references in modules:"
rg -n -C2 '\bRolesGuard\b' backend/src --glob '**/*.module.ts' || true

echo
echo "RolesGuard use sites:"
rg -n -C2 '@UseGuards\([^)]*\bRolesGuard\b' backend/src --type=ts || true

echo
echo "AuthModule wiring:"
sed -n '1,200p' backend/src/auth/auth.module.ts

Repository: OlufunbiIK/tip-tune

Length of output: 6982


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Finding RolesGuard file ==="
fd -type f -name '*roles.guard*' backend/src

echo
echo "=== RolesGuard implementation ==="
cat -n backend/src/auth/guards/roles.guard.ts

echo
echo "=== Checking if RolesGuard is exported from any index/barrel file ==="
rg -n 'RolesGuard' backend/src --glob '**/*index*' || true

echo
echo "=== Checking if RolesGuard appears in any .module.ts ==="
rg -n 'RolesGuard' backend/src --glob '**/*.module.ts' || true

echo
echo "=== Checking RolesGuard in auth.module.ts (full file) ==="
wc -l backend/src/auth/auth.module.ts

Repository: OlufunbiIK/tip-tune

Length of output: 282


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Finding RolesGuard file ==="
find backend/src -name '*roles.guard*'

echo
echo "=== RolesGuard implementation ==="
cat -n backend/src/auth/guards/roles.guard.ts

echo
echo "=== Checking all .module.ts files for RolesGuard ==="
rg 'RolesGuard' backend/src --type ts -l

echo
echo "=== Full AuthModule file ==="
cat -n backend/src/auth/auth.module.ts

Repository: OlufunbiIK/tip-tune

Length of output: 3269


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Checking app.module.ts ==="
find backend/src -name 'app.module.ts' -exec cat -n {} \;

echo
echo "=== Searching for RolesGuard in any import/provider context ==="
rg -B3 -A3 'RolesGuard' backend/src --type ts --glob '**/*.ts' | grep -E '(providers|imports|@Module)' || true

Repository: OlufunbiIK/tip-tune

Length of output: 6788


RolesGuard must be added to AuthModule's providers and exports.

RolesGuard is @Injectable() and depends on @InjectRepository(User), but is not registered in any module's providers array. It is currently used via @UseGuards(RolesGuard) across 15+ routes in ReportsModule, ModerationModule, FeesModule, platinum-fee, and VerificationModule, but these controllers cannot resolve it at runtime.

To fix, add RolesGuard to AuthModule.providers and AuthModule.exports:

`@Module`({
  imports: [TypeOrmModule.forFeature([User]), ...],
  providers: [AuthService, WalletStrategy, JwtAuthGuard, RolesGuard],
  exports: [AuthService, JwtAuthGuard, WalletStrategy, RolesGuard],
})
export class AuthModule {}

Then import AuthModule into any module that uses @UseGuards(RolesGuard), or export RolesGuard from a shared guards module.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/auth/guards/roles.guard.ts` around lines 9 - 12, RolesGuard is
injectable and injects User repository but isn't provided by any module, causing
runtime resolution failures where controllers use `@UseGuards`(RolesGuard); add
RolesGuard to the AuthModule providers and exports (alongside
TypeOrmModule.forFeature([User]) and existing providers like AuthService and
JwtAuthGuard) so it can be injected, then ensure modules using
`@UseGuards`(RolesGuard) import AuthModule (or export RolesGuard from a shared
guards module) so RolesGuard can be resolved at runtime.

Comment on lines +29 to 31
async createTier(@Body() dto: CreateSubscriptionTierDto) {
// Enforce that the artistId in the DTO matches the requesting artist
return this.subscriptionsService.createTier(dto);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "DTO fields:"
rg -n -C2 'class CreateSubscriptionTierDto|class UpdateSubscriptionTierDto|artistId' \
  backend/src/subscription-tiers/subscriptions.dto.ts

echo
echo "Tier mutation controller/service flow:"
rg -n -C3 'createTier\(|updateTier\(|deleteTier\(' \
  backend/src/subscription-tiers/subscriptions.controller.ts \
  backend/src/subscription-tiers/subscriptions.service.ts

Repository: OlufunbiIK/tip-tune

Length of output: 5051


🏁 Script executed:

cat -n backend/src/subscription-tiers/subscriptions.dto.ts

Repository: OlufunbiIK/tip-tune

Length of output: 2859


🏁 Script executed:

cat -n backend/src/auth/decorators/current-user.decorator.ts

Repository: OlufunbiIK/tip-tune

Length of output: 946


🏁 Script executed:

rg -n 'artistId' backend/src/subscription-tiers/subscriptions.dto.ts

Repository: OlufunbiIK/tip-tune

Length of output: 85


🏁 Script executed:

cat -n backend/src/subscription-tiers/subscriptions.service.ts | head -100

Repository: OlufunbiIK/tip-tune

Length of output: 4035


🏁 Script executed:

rg -n "artistId|userId" backend/src/subscription-tiers/subscriptions.service.ts | head -30

Repository: OlufunbiIK/tip-tune

Length of output: 1055


🏁 Script executed:

fd -t f "user.*\.(ts|entity)" backend/src/ | head -10

Repository: OlufunbiIK/tip-tune

Length of output: 553


🏁 Script executed:

rg -l "entity|Entity" backend/src/ | grep -i user | head -5

Repository: OlufunbiIK/tip-tune

Length of output: 251


🏁 Script executed:

cat -n backend/src/users/entities/user.entity.ts

Repository: OlufunbiIK/tip-tune

Length of output: 1892


🏁 Script executed:

rg -n "artistId|isArtist" backend/src/users/entities/user.entity.ts

Repository: OlufunbiIK/tip-tune

Length of output: 86


🏁 Script executed:

fd -t f "artist.*entity" backend/src/ -o fd -t f "profile.*entity" backend/src/ | head -10

Repository: OlufunbiIK/tip-tune

Length of output: 186


🏁 Script executed:

rg -l "artistId|ArtistId" backend/src/ --type ts | grep -i "entity\|model" | head -10

Repository: OlufunbiIK/tip-tune

Length of output: 607


🏁 Script executed:

cat -n backend/src/subscription-tiers/subscription-tier.entity.ts

Repository: OlufunbiIK/tip-tune

Length of output: 1775


🏁 Script executed:

rg -n "userId|artistId" backend/src/subscription-tiers/subscription-tier.entity.ts

Repository: OlufunbiIK/tip-tune

Length of output: 85


Don't take artistId from the request body for tier mutations.

These endpoints are artist-owned actions, but artistId is entirely client-controlled via the request. createTier spreads a DTO with artistId: string directly into the tier, updateTier calls service.updateTier(tierId, dto.artistId, ...) even though UpdateSubscriptionTierDto has no artistId field (causing a TypeScript TS2339 error), and deleteTier accepts artistId from the request body. Because the service authorizes by comparing the supplied artistId to tier.artistId, callers can spoof any artist's tier.

Resolve ownership from @CurrentUser("userId") instead. Since artists are identified by their user ID (the isArtist boolean flag exists), pass userId to the service methods and perform the ownership check against tier.artistId === userId.

🔐 Suggested fix
  `@Post`("tiers")
-  async createTier(`@Body`() dto: CreateSubscriptionTierDto) {
-    // Enforce that the artistId in the DTO matches the requesting artist
-    return this.subscriptionsService.createTier(dto);
+  async createTier(
+    `@CurrentUser`("userId") userId: string,
+    `@Body`() dto: CreateSubscriptionTierDto,
+  ) {
+    return this.subscriptionsService.createTier(userId, dto);
  }

  `@Patch`("tiers/:tierId")
  async updateTier(
    `@Param`("tierId", ParseUUIDPipe) tierId: string,
+    `@CurrentUser`("userId") userId: string,
    `@Body`() dto: UpdateSubscriptionTierDto,
  ) {
-    // Note: artist ownership should be enforced in service using user context if needed
-    return this.subscriptionsService.updateTier(tierId, dto.artistId, dto);
+    return this.subscriptionsService.updateTier(tierId, userId, dto);
  }

  `@Delete`("tiers/:tierId")
  `@HttpCode`(HttpStatus.NO_CONTENT)
-  async deleteTier(`@Param`("tierId", ParseUUIDPipe) tierId: string, `@Body`() body: { artistId: string }) {
-    await this.subscriptionsService.deleteTier(tierId, body.artistId);
+  async deleteTier(
+    `@Param`("tierId", ParseUUIDPipe) tierId: string,
+    `@CurrentUser`("userId") userId: string,
+  ) {
+    await this.subscriptionsService.deleteTier(tierId, userId);
+  }

Also applies to: 52–53, 62–63

@OlufunbiIK OlufunbiIK merged commit 8ab2fb3 into OlufunbiIK:main Mar 29, 2026
1 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants