Skip to content

feat(profile): implement user profile system#68

Closed
bernardev254 wants to merge 2 commits intoStellar-Rent:mainfrom
bernardev254:profile-management-clean
Closed

feat(profile): implement user profile system#68
bernardev254 wants to merge 2 commits intoStellar-Rent:mainfrom
bernardev254:profile-management-clean

Conversation

@bernardev254
Copy link
Contributor

@bernardev254 bernardev254 commented Jun 4, 2025

StellarRent Logo

Pull Request | StellarRent

📝 Summary

This PR implements the user profile management system, enabling users to view, update, and delete their profile, as well as upload a profile avatar. It enforces type safety and improves error handling for interactions with the Supabase backend.

🔗 Related Issues

Closes #44

🔄 Changes Made

  1. Added profile.controller.ts with routes for:
  • getProfile
  • updateProfile
  • deleteAccount
  • uploadAvatar
  1. Implemented profile.service.ts functions for:
  • Fetching user profiles from Supabase
  • Updating profiles with strict types (UserProfile)
  • Deleting accounts
  • Uploading avatar images to Supabase storage
  1. Integrated Supabase public URL retrieval after avatar upload

  2. Fixed type issues flagged by Biome and enforced interface usage for profile data

🖼️ Current Output

Provide visual evidence of the changes:

  • For small changes: Screenshots.
  • For large changes: Video or Loom link.

🧪 Testing

If applicable, describe the tests performed. Include screenshots, test outputs, or any resources that help reviewers understand how the changes were tested.

✅ Testing Checklist

  • Unit tests added/modified
  • Integration tests performed
  • Manual tests executed
  • All tests pass in CI/CD

⚠️ Potential Risks

List any possible issues that might arise with this change.

🚀 Next Steps & Improvements

This change lays a solid foundation for further optimizations. Some areas that could benefit from future improvements include:

  • 🔹 Performance optimization
  • 🔹 Increased test coverage
  • 🔹 Potential user experience enhancements

💬 Comments

Any additional context, questions, or considerations for reviewers.

Summary by CodeRabbit

  • New Features

    • Introduced user profile management endpoints, allowing users to view, update, and delete their profiles, as well as upload avatar images.
    • Added file upload support for profile avatars using in-memory storage.
    • Implemented database initialization to ensure the required profiles table is created at startup.
  • Enhancements

    • Expanded user profile structure to support additional fields such as address, preferences, social links, verification status, and last active timestamp.
    • Updated authentication to use Supabase's built-in authentication and user management.
    • Improved token authentication by integrating Supabase user verification.
  • Bug Fixes

    • Improved error handling and response consistency for authentication and profile-related endpoints.
  • Chores

    • Updated environment and configuration files for clarity and consistency.
    • Refactored and reorganized routes, controllers, and middleware for better maintainability and structure.
    • Added and updated TypeScript types and interfaces for improved type safety.
    • Reformatted ESLint configuration for consistent style.
    • Upgraded backend package dependencies.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 4, 2025

Walkthrough

This update introduces a comprehensive user profile system to the backend application. It adds new profile-related routes and controllers, expands the user profile schema, integrates Supabase authentication and storage, and implements middleware for authentication and file uploads. The database schema and service logic are refactored to support extended profile fields and avatar uploads.

Changes

File(s) Change Summary
.env.example, .eslintrc.json, package.json Added SUPABASE_DB_URL env var; reformatted ESLint config; updated multer dependency version.
src/config/supabase.ts, src/db/init.ts, src/types/userProfile.ts Refactored schema: renamed users→profiles, expanded fields, added DB init script, introduced UserProfileUpdate type.
src/controllers/auth.controller.ts, src/controllers/profile.controller.ts Added/rewrote controllers for auth and new profile endpoints.
src/controllers/authController.ts Removed legacy auth controller.
src/routes/auth.ts, src/routes/profile.routes.ts, src/routes/index.ts Updated and added routers for auth and profile endpoints, consolidated routing.
src/services/auth.service.ts, src/services/profile.service.ts, src/services/a.ts Refactored auth service to use Supabase, added profile CRUD and avatar upload services.
src/middleware/auth.middleware.ts, src/middleware/multer.ts Refactored auth middleware for Supabase, added multer-based file upload middleware.
src/types/auth.types.ts, src/types/express/index.d.ts Updated types for extended profiles and Express request augmentation.
src/validators/auth.validator.ts Simplified validator function signatures.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant API
    participant AuthMiddleware
    participant Supabase
    participant ProfileService
    participant Storage

    Client->>API: PATCH /profile (with JWT)
    API->>AuthMiddleware: Authenticate token
    AuthMiddleware->>Supabase: getUser(token)
    Supabase-->>AuthMiddleware: user object
    AuthMiddleware-->>API: attach user to req
    API->>ProfileService: updateUserProfile(userId, updates)
    ProfileService->>Supabase: Update profiles table
    Supabase-->>ProfileService: Updated profile
    ProfileService-->>API: profile
    API-->>Client: 200 OK + updated profile

    Client->>API: POST /profile/avatar (with file)
    API->>AuthMiddleware: Authenticate token
    AuthMiddleware->>Supabase: getUser(token)
    Supabase-->>AuthMiddleware: user object
    AuthMiddleware-->>API: attach user to req
    API->>ProfileService: uploadUserAvatar(userId, req)
    ProfileService->>Storage: Upload file to Supabase storage
    Storage-->>ProfileService: avatar_url
    ProfileService->>Supabase: Update profiles.avatar_url
    Supabase-->>ProfileService: Updated profile
    ProfileService-->>API: avatar_url
    API-->>Client: 200 OK + avatar_url
Loading

Assessment against linked issues

Objective Addressed Explanation
Profile Management endpoints: GET/PATCH/DELETE /profile, POST /profile/avatar (#44)
Profile Fields Extension: Extended UserProfile structure with nested fields and status (#44)
Security Enhancements: Email/phone verification, 2FA, session management, activity logging (#44) Only basic session/auth provided; no explicit email/phone verification, 2FA, or logging implemented.
Advanced Features: Profile completion %, badges, last active, login/device history, notification prefs (#44) Only last_active is implemented; other advanced features are not present.
Integration Points: Listings, reviews, booking, payment, saved properties (#44) No integration features implemented.

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Added/updated .env.example, .eslintrc.json, package.json (apps/backend/) These changes are general improvements and dependency updates, not directly related to user profile objectives.
Simplified validator function signatures (src/validators/auth.validator.ts) This is a code style/clarity change, not directly tied to profile system requirements.

Possibly related PRs

  • Stellar-Rent/stellar-rent#14: Refactored initial authentication and user management logic, which is directly replaced and expanded upon in this PR.

Poem

In the backend burrow, profiles bloom anew,
With avatars and fields, and preferences too!
Supabase lends a paw, for auth and for store,
Multer helps with files, hopping through the door.
Now every bunny’s profile, is richer than before!
🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b57a3dc and 721d79d.

📒 Files selected for processing (4)
  • apps/backend/.env.example (1 hunks)
  • apps/backend/package.json (1 hunks)
  • apps/backend/src/config/supabase.ts (1 hunks)
  • apps/backend/src/index.ts (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/backend/.env.example
  • apps/backend/package.json
  • apps/backend/src/index.ts
  • apps/backend/src/config/supabase.ts
✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@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: 19

🧹 Nitpick comments (7)
apps/backend/.eslintrc.json (1)

13-16: Avoid duplicate no-unused-vars rules
The base ESLint rule overlaps with the TS-specific rule, which can lead to redundant warnings. Consider disabling the core rule instead:

 {
   "rules": {
-    "no-unused-vars": "warn",
+    "no-unused-vars": "off",
     "@typescript-eslint/no-unused-vars": "warn"
   }
 }
apps/backend/src/types/userProfile.ts (1)

1-24: Consider adding validation constraints and addressing potential serialization issues.

The interface structure is comprehensive, but there are a few areas for improvement:

  1. Empty updates: All fields being optional allows empty update objects
  2. Date serialization: The Date type may cause issues in JSON serialization/deserialization

Consider these improvements:

export interface UserProfileUpdate {
  email?: string;
  name?: string;
  avatar_url?: string;
  phone?: string;
  address?: {
    street?: string;
    city?: string;
    country?: string;
    postal_code?: string;
  };
  preferences?: {
    notifications?: boolean;
    newsletter?: boolean;
    language?: string;
  };
  social_links?: {
    facebook?: string;
    twitter?: string;
    instagram?: string;
  };
  verification_status?: 'unverified' | 'pending' | 'verified';
-  last_active?: Date;
+  last_active?: string; // ISO string format for JSON compatibility
}

+// Helper type to ensure at least one field is provided
+export type ValidUserProfileUpdate = UserProfileUpdate & {
+  [K in keyof UserProfileUpdate]: UserProfileUpdate[K] extends undefined ? never : UserProfileUpdate[K];
+}[keyof UserProfileUpdate] extends never ? never : UserProfileUpdate;
apps/backend/src/db/init.ts (2)

12-24: Consider adding indexes for better query performance.

The current schema lacks indexes on frequently queried columns like verification_status and last_active, which could impact performance as the user base grows.

Add indexes after table creation:

      );
    `);

+    await client.query(`
+      CREATE INDEX IF NOT EXISTS idx_profiles_verification_status 
+      ON public.profiles(verification_status);
+      
+      CREATE INDEX IF NOT EXISTS idx_profiles_last_active 
+      ON public.profiles(last_active);
+    `);

26-31: Improve error logging and add connection retry logic.

The current error handling logs errors but doesn't distinguish between different failure types. Consider adding more specific error handling and retry logic for transient connection issues.

Enhance error handling:

  } catch (error) {
-    console.error('❌ Failed to initialize DB:', error);
+    console.error('❌ Failed to initialize DB:', {
+      message: error instanceof Error ? error.message : 'Unknown error',
+      code: error instanceof Error && 'code' in error ? error.code : undefined,
+    });
+    throw error; // Re-throw to allow caller to handle initialization failure
  } finally {
-    await client.end();
+    try {
+      await client.end();
+    } catch (closeError) {
+      console.warn('Warning: Failed to close database connection:', closeError);
+    }
  }
apps/backend/src/controllers/profile.controller.ts (1)

36-43: Improve error handling consistency in uploadAvatar.

The function follows the same pattern as others but should provide more specific error messages for file upload issues.

Enhance error handling for file uploads:

export const uploadAvatar = async (req: Request, res: Response) => {
  if (!req.user) return res.status(401).json({ error: 'Usuario no autenticado' });

  const result = await uploadUserAvatar(req.user.id, req);
-  if (result.error) return res.status(400).json({ error: result.error.message });
+  if (result.error) {
+    const errorMessage = result.error.message;
+    if (errorMessage.includes('No file uploaded')) {
+      return res.status(400).json({ error: 'No se subió ningún archivo' });
+    }
+    if (errorMessage.includes('Invalid file type')) {
+      return res.status(400).json({ error: 'Tipo de archivo no válido' });
+    }
+    if (errorMessage.includes('File size exceeds')) {
+      return res.status(413).json({ error: 'Archivo demasiado grande' });
+    }
+    return res.status(500).json({ error: 'Error al subir avatar' });
+  }

  res.json({ avatar_url: result.avatar_url });
};
apps/backend/src/types/auth.types.ts (1)

57-57: Consider adding JSDoc comment for last_active field.

Since last_active stores ISO date strings, adding documentation would improve clarity for other developers.

-  last_active: string;
+  /** ISO 8601 date string representing the user's last activity */
+  last_active: string;
apps/backend/src/config/supabase.ts (1)

30-30: Consider using timestamp type in the database schema.

While storing dates as ISO strings works, using a proper timestamp or timestamptz column type in the database would provide better performance for date-based queries and automatic timezone handling.

If you need to keep the string type for compatibility, consider adding a database-level constraint to validate ISO format or creating an index on this column for better query performance.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a4ef212 and b57a3dc.

📒 Files selected for processing (21)
  • apps/backend/.env.example (1 hunks)
  • apps/backend/.eslintrc.json (1 hunks)
  • apps/backend/package.json (1 hunks)
  • apps/backend/src/config/supabase.ts (1 hunks)
  • apps/backend/src/controllers/auth.controller.ts (1 hunks)
  • apps/backend/src/controllers/authController.ts (0 hunks)
  • apps/backend/src/controllers/profile.controller.ts (1 hunks)
  • apps/backend/src/db/init.ts (1 hunks)
  • apps/backend/src/index.ts (4 hunks)
  • apps/backend/src/middleware/auth.middleware.ts (1 hunks)
  • apps/backend/src/middleware/multer.ts (1 hunks)
  • apps/backend/src/routes/auth.ts (1 hunks)
  • apps/backend/src/routes/index.ts (1 hunks)
  • apps/backend/src/routes/profile.routes.ts (1 hunks)
  • apps/backend/src/services/a.ts (1 hunks)
  • apps/backend/src/services/auth.service.ts (1 hunks)
  • apps/backend/src/services/profile.service.ts (1 hunks)
  • apps/backend/src/types/auth.types.ts (1 hunks)
  • apps/backend/src/types/express/index.d.ts (1 hunks)
  • apps/backend/src/types/userProfile.ts (1 hunks)
  • apps/backend/src/validators/auth.validator.ts (2 hunks)
💤 Files with no reviewable changes (1)
  • apps/backend/src/controllers/authController.ts
🧰 Additional context used
🧬 Code Graph Analysis (8)
apps/backend/src/routes/auth.ts (2)
apps/backend/src/validators/auth.validator.ts (2)
  • validateLogin (5-18)
  • validateRegister (20-33)
apps/backend/src/controllers/auth.controller.ts (2)
  • login (23-38)
  • register (4-21)
apps/backend/src/routes/profile.routes.ts (3)
apps/backend/src/middleware/auth.middleware.ts (1)
  • authenticateToken (4-25)
apps/backend/src/controllers/profile.controller.ts (4)
  • getProfile (9-16)
  • updateProfile (18-25)
  • deleteAccount (27-34)
  • uploadAvatar (36-43)
apps/backend/src/middleware/multer.ts (1)
  • upload (4-4)
apps/backend/src/types/express/index.d.ts (1)
apps/backend/src/types/auth.types.ts (1)
  • User (11-15)
apps/backend/src/index.ts (1)
apps/backend/src/db/init.ts (1)
  • initializeDatabase (4-32)
apps/backend/src/controllers/profile.controller.ts (1)
apps/backend/src/services/profile.service.ts (4)
  • getUserProfile (5-9)
  • updateUserProfile (11-19)
  • deleteUserAccount (21-24)
  • uploadUserAvatar (26-50)
apps/backend/src/services/auth.service.ts (2)
apps/backend/src/config/supabase.ts (1)
  • supabase (49-61)
apps/backend/src/types/auth.types.ts (1)
  • AuthResponse (66-69)
apps/backend/src/controllers/auth.controller.ts (1)
apps/backend/src/services/auth.service.ts (2)
  • registerUser (15-69)
  • loginUser (11-13)
apps/backend/src/middleware/auth.middleware.ts (1)
apps/backend/src/config/supabase.ts (1)
  • supabase (49-61)
🔇 Additional comments (15)
apps/backend/.eslintrc.json (5)

2-5: Valid environment configuration
Enabling node and es2021 environments aligns with the backend’s runtime and language target.


6-6: Extends are correct
Combining eslint:recommended with plugin:@typescript-eslint/recommended ensures both core and TS-specific linting rules are applied.


7-7: Parser configuration is correct
Using @typescript-eslint/parser is required for parsing TypeScript syntax.


8-11: Parser options are consistent
Specifying ecmaVersion: 12 (ES2021) and sourceType: "module" matches the project’s module system and language features.


12-12: Plugin declaration is correct
Including the @typescript-eslint plugin is necessary for the TS ruleset.

apps/backend/package.json (1)

22-22:

Details

✅ Verification successful

Verify the multer package version for validity and security.

Please ensure that multer version 2.0.0 exists and check for any associated security vulnerabilities.


🏁 Script executed:

#!/bin/bash
# Description: Verify multer package version and check for security advisories

# Check latest version available on npm
curl -s https://registry.npmjs.org/multer | jq '.["dist-tags"].latest'

# Check if version 2.0.0 exists
curl -s https://registry.npmjs.org/multer | jq '.versions | has("2.0.0")'

# Check for security advisories
gh api graphql -f query='
{
  securityVulnerabilities(first: 5, ecosystem: NPM, package: "multer") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}'

Length of output: 991


Multer dependency version validated

  • Version 2.0.0 exists and is the first patched release for the reported high-severity DoS vulnerabilities (both fixed in 2.0.0).
  • The caret range (^2.0.0) will pull in the patched 2.0.0 and any later 2.x (latest is 2.0.1).

No further changes needed.

apps/backend/.env.example (1)

5-5: LGTM: Service role key addition is appropriate.

The addition of SUPABASE_SERVICE_ROLE_KEY is correct for service-level operations with Supabase.

apps/backend/src/routes/auth.ts (2)

2-2: LGTM: Import path update aligns with new file structure.

The updated import path correctly reflects the new controller file naming convention.


5-10: LGTM: Router refactoring improves code clarity.

The router renaming from router to authRouter provides better semantic meaning and aligns with modern naming conventions.

apps/backend/src/routes/index.ts (1)

1-11: LGTM! Clean and well-organized routing structure.

The consolidated router approach with clear prefixes and helpful comments provides good organization for the API endpoints.

apps/backend/src/types/express/index.d.ts (2)

6-7: LGTM! Proper type extensions for middleware integration.

The optional properties correctly support the authentication middleware (user) and file upload middleware (file) without breaking existing code.


2-2:

Details

❌ Incorrect review comment

Verify User type consistency across the application.

The import uses User from @supabase/supabase-js, but there's also a local User interface defined in apps/backend/src/types/auth.types.ts. Ensure there are no type conflicts and that the application consistently uses the intended User type.


🏁 Script executed:

#!/bin/bash
# Description: Check for User type usage conflicts between local and Supabase types
# Expected: Verify which User type is used where and if there are any conflicts

# Search for local User interface definition
echo "=== Local User interface definition ==="
rg -A 5 "interface User" --type ts

echo -e "\n=== User type imports from Supabase ==="
rg "import.*User.*@supabase" --type ts

echo -e "\n=== User type imports from local files ==="
rg "import.*User.*\.\/" --type ts

echo -e "\n=== User type usage in code ==="
rg ": User[^a-zA-Z]" --type ts -A 2

Length of output: 2261


I’ll check where (and if) the local User interface is actually imported and used in the backend:


🏁 Script executed:

#!/bin/bash
echo "=== Imports of local User from auth.types.ts ==="
rg "import.*User.*auth.types" --type ts

echo -e "\n=== Imports of User from local files (excluding Supabase) ==="
rg "import.*User.*'\." --type ts | grep -v supabase

Length of output: 662


No action needed: backend exclusively uses Supabase User type

The backend’s Express.Request.user is typed with User from @supabase/supabase-js, and the local User interface in
apps/backend/src/types/auth.types.ts is never imported or used in the backend. There’s no conflicting usage—feel free to ignore the original conflict warning.

Likely an incorrect or invalid review comment.

apps/backend/src/validators/auth.validator.ts (1)

5-5: LGTM! Improved code formatting.

The simplified function signatures enhance readability while maintaining the same validation logic.

Also applies to: 20-20

apps/backend/src/routes/profile.routes.ts (1)

1-19: LGTM! Clean and well-structured profile routing implementation.

The profile routes are well-organized with proper authentication middleware applied to all endpoints. The use of appropriate HTTP methods (GET for retrieval, PATCH for updates, DELETE for account deletion, and POST for avatar uploads) follows RESTful conventions. The avatar upload route correctly integrates the multer middleware for file handling.

apps/backend/src/middleware/auth.middleware.ts (1)

4-25: Excellent refactoring to use Supabase authentication!

The migration from manual JWT verification to Supabase's built-in auth.getUser() method is a significant improvement. This approach:

  • Leverages Supabase's robust token validation
  • Eliminates the need for manual JWT secret management
  • Provides better integration with Supabase's user management system
  • Simplifies the authentication flow

The implementation correctly handles token extraction, validation, and user attachment to the request object.

CLOUDINARY_CLOUD_NAME=cloudinary_cloud_name
CLOUDINARY_API_KEY=cloudinary_api_key
CLOUDINARY_API_SECRET=cloudinary_api_secret
SUPABASE_DB_URL=postgresql No newline at end of file
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Fix the database URL example format.

The current value postgresql is not a valid PostgreSQL connection string format. This could mislead developers about the expected format.

-SUPABASE_DB_URL=postgresql
+SUPABASE_DB_URL=postgresql://username:password@hostname:port/database
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
SUPABASE_DB_URL=postgresql
SUPABASE_DB_URL=postgresql://username:password@hostname:port/database
🤖 Prompt for AI Agents
In apps/backend/.env.example at line 6, the SUPABASE_DB_URL value is set to
"postgresql", which is not a valid PostgreSQL connection string format. Replace
this placeholder with a properly formatted example connection string, such as
"postgresql://user:password@host:port/database", to clearly demonstrate the
expected format to developers.

Comment on lines +3 to +4
const storage = multer.memoryStorage(); // store in memory before upload to Supabase
export const upload = multer({ storage });
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add essential security and performance configurations.

The current multer configuration lacks important security and performance safeguards that could lead to memory exhaustion or malicious file uploads.

-const storage = multer.memoryStorage(); // store in memory before upload to Supabase
-export const upload = multer({ storage });
+const storage = multer.memoryStorage();
+
+export const upload = multer({ 
+  storage,
+  limits: {
+    fileSize: 5 * 1024 * 1024, // 5MB limit
+    files: 1
+  },
+  fileFilter: (req, file, cb) => {
+    // Only allow image files for avatars
+    if (file.mimetype.startsWith('image/')) {
+      cb(null, true);
+    } else {
+      cb(new Error('Only image files are allowed'));
+    }
+  }
+});

This adds:

  • File size limit (5MB) to prevent memory exhaustion
  • Single file limit for avatar uploads
  • Image file type validation for security
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const storage = multer.memoryStorage(); // store in memory before upload to Supabase
export const upload = multer({ storage });
const storage = multer.memoryStorage();
export const upload = multer({
storage,
limits: {
fileSize: 5 * 1024 * 1024, // 5MB limit
files: 1
},
fileFilter: (req, file, cb) => {
// Only allow image files for avatars
if (file.mimetype.startsWith('image/')) {
cb(null, true);
} else {
cb(new Error('Only image files are allowed'));
}
}
});
🤖 Prompt for AI Agents
In apps/backend/src/middleware/multer.ts around lines 3 to 4, the multer
configuration is missing critical security and performance settings. Update the
multer setup to include a file size limit of 5MB to prevent memory exhaustion,
restrict uploads to a single file for avatar uploads, and add validation to
allow only image file types for security. Implement these constraints within the
multer options to enhance safety and resource management.

Comment on lines +1 to +11
import type { UserProfileUpdate } from '../types/userProfile';

export const updateUserProfile = async (userId: string, updates: UserProfileUpdate) => {
const { data, error } = await supabase
.from('profiles')
.update({ ...updates, last_active: new Date().toISOString() })
.eq('user_id', userId)
.single();

return error ? { error } : { profile: data };
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical: Fix filename and missing import.

This file has two critical issues:

  1. Inappropriate filename: The file is named a.ts which should be properly named (e.g., profile.service.ts)
  2. Missing import: The supabase client is used but not imported, which will cause a runtime error

Add the missing import at the top of the file:

+import { supabase } from '../config/supabase';
 import type { UserProfileUpdate } from '../types/userProfile';

Also rename this file to a more descriptive name like profile.service.ts or integrate this function into the existing profile service file.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import type { UserProfileUpdate } from '../types/userProfile';
export const updateUserProfile = async (userId: string, updates: UserProfileUpdate) => {
const { data, error } = await supabase
.from('profiles')
.update({ ...updates, last_active: new Date().toISOString() })
.eq('user_id', userId)
.single();
return error ? { error } : { profile: data };
};
import { supabase } from '../config/supabase';
import type { UserProfileUpdate } from '../types/userProfile';
export const updateUserProfile = async (userId: string, updates: UserProfileUpdate) => {
const { data, error } = await supabase
.from('profiles')
.update({ ...updates, last_active: new Date().toISOString() })
.eq('user_id', userId)
.single();
return error ? { error } : { profile: data };
};
🤖 Prompt for AI Agents
In apps/backend/src/services/a.ts lines 1 to 11, rename the file from a.ts to a
more descriptive name like profile.service.ts to reflect its purpose. Also, add
the missing import statement for the supabase client at the top of the file to
avoid runtime errors when calling supabase methods.

Comment on lines 54 to 59
// Initialize DB and then start server
initializeDatabase().then(() => {
app.listen(PORT, () => {
console.log(`🚀 Server running on http://localhost:${PORT}`);
});
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider adding error handling for database initialization.

The database initialization should handle potential failures gracefully to prevent the server from starting with an uninitialized database.

Add error handling:

// Initialize DB and then start server
-initializeDatabase().then(() => {
-  app.listen(PORT, () => {
-    console.log(`🚀 Server running on http://localhost:${PORT}`);
-  });
-});
+initializeDatabase()
+  .then(() => {
+    app.listen(PORT, () => {
+      console.log(`🚀 Server running on http://localhost:${PORT}`);
+    });
+  })
+  .catch((error) => {
+    console.error('Failed to initialize database:', error);
+    process.exit(1);
+  });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Initialize DB and then start server
initializeDatabase().then(() => {
app.listen(PORT, () => {
console.log(`🚀 Server running on http://localhost:${PORT}`);
});
});
// Initialize DB and then start server
initializeDatabase()
.then(() => {
app.listen(PORT, () => {
console.log(`🚀 Server running on http://localhost:${PORT}`);
});
})
.catch((error) => {
console.error('Failed to initialize database:', error);
process.exit(1);
});
🤖 Prompt for AI Agents
In apps/backend/src/index.ts around lines 54 to 59, the database initialization
lacks error handling, which could lead to the server starting without a properly
initialized database. Modify the promise chain to include a catch block that
logs the error and prevents the server from starting if initialization fails.
This ensures the server only starts when the database is successfully
initialized and errors are properly reported.

Comment on lines +27 to +32
const router = Router();

// Apply prefixes here
router.use('/auth', authRouter);
router.use('/profile', profileRouter);

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove redundant router creation.

The new router instance and manual mounting of individual routers is redundant if you're already using the consolidated routes module at line 44.

If using the consolidated routes approach, remove this section:

-const router = Router();
-
-// Apply prefixes here
-router.use('/auth', authRouter);
-router.use('/profile', profileRouter);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const router = Router();
// Apply prefixes here
router.use('/auth', authRouter);
router.use('/profile', profileRouter);
🤖 Prompt for AI Agents
In apps/backend/src/index.ts around lines 27 to 32, remove the redundant
creation of a new router instance and the manual mounting of individual routers
like '/auth' and '/profile' since the consolidated routes module imported and
used at line 44 already handles these. Delete the lines that create the router
and call router.use for these routes to avoid duplication.

Comment on lines +27 to +34
export const deleteAccount = async (req: Request, res: Response) => {
if (!req.user) return res.status(401).json({ error: 'Usuario no autenticado' });

const result = await deleteUserAccount(req.user.id);
if (result.error) return res.status(400).json({ error: result.error.message });

res.json({ message: 'Cuenta eliminada' });
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add confirmation requirement for account deletion.

Account deletion is a destructive operation that should require explicit confirmation to prevent accidental deletions.

Add confirmation requirement:

export const deleteAccount = async (req: Request, res: Response) => {
  if (!req.user) return res.status(401).json({ error: 'Usuario no autenticado' });

+  const { confirmation } = req.body;
+  if (!confirmation || confirmation !== 'DELETE_MY_ACCOUNT') {
+    return res.status(400).json({ 
+      error: 'Se requiere confirmación explícita para eliminar la cuenta' 
+    });
+  }

-  const result = await deleteUserAccount(req.user.id);
+  const result = await deleteUserAccount(req.user.id, true);
-  if (result.error) return res.status(400).json({ error: result.error.message });
+  if (result.error) {
+    return res.status(500).json({ error: 'Error al eliminar cuenta' });
+  }

  res.json({ message: 'Cuenta eliminada' });
};

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In apps/backend/src/controllers/profile.controller.ts around lines 27 to 34, the
deleteAccount function currently deletes the user account immediately without
confirmation. Modify the function to require an explicit confirmation parameter
(e.g., a confirmation flag or token) in the request body or query. Check for
this confirmation before proceeding with deletion, and if it is missing or
false, respond with an error status and message asking the user to confirm the
deletion. This will prevent accidental account deletions.

Comment on lines +22 to 31
export const registerSchema = z.object({
email: z.string().email(),
password: z.string().min(6),
name: z.string(),
avatar_url: z.string().url().optional(),
phone: z.string().optional(),
address: z.any().optional(), // ideally make this stricter
preferences: z.any().optional(),
social_links: z.any().optional(),
});
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Replace z.any() with proper type validation for nested objects.

Using z.any() for address, preferences, and social_links bypasses validation and type safety. These fields should have proper schema definitions that match the PublicProfile interface structure.

 export const registerSchema = z.object({
   email: z.string().email(),
   password: z.string().min(6),
   name: z.string(),
   avatar_url: z.string().url().optional(),
   phone: z.string().optional(),
-  address: z.any().optional(), // ideally make this stricter
+  address: z.object({
+    street: z.string(),
+    city: z.string(),
+    country: z.string(),
+    postal_code: z.string(),
+  }).optional(),
-  preferences: z.any().optional(),
+  preferences: z.object({
+    notifications: z.boolean(),
+    newsletter: z.boolean(),
+    language: z.string(),
+  }).optional(),
-  social_links: z.any().optional(),
+  social_links: z.object({
+    facebook: z.string().url().optional(),
+    twitter: z.string().url().optional(),
+    instagram: z.string().url().optional(),
+  }).optional(),
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const registerSchema = z.object({
email: z.string().email(),
password: z.string().min(6),
name: z.string(),
avatar_url: z.string().url().optional(),
phone: z.string().optional(),
address: z.any().optional(), // ideally make this stricter
preferences: z.any().optional(),
social_links: z.any().optional(),
});
export const registerSchema = z.object({
email: z.string().email(),
password: z.string().min(6),
name: z.string(),
avatar_url: z.string().url().optional(),
phone: z.string().optional(),
address: z.object({
street: z.string(),
city: z.string(),
country: z.string(),
postal_code: z.string(),
}).optional(),
preferences: z.object({
notifications: z.boolean(),
newsletter: z.boolean(),
language: z.string(),
}).optional(),
social_links: z.object({
facebook: z.string().url().optional(),
twitter: z.string().url().optional(),
instagram: z.string().url().optional(),
}).optional(),
});
🤖 Prompt for AI Agents
In apps/backend/src/types/auth.types.ts between lines 22 and 31, replace the use
of z.any() for the address, preferences, and social_links fields with detailed
zod schema definitions that reflect the expected structure of these nested
objects according to the PublicProfile interface. Define proper nested object
schemas using z.object() with appropriate field validations to ensure type
safety and validation coverage.

Comment on lines +71 to +183
// export const loginUser = async (input: LoginInput): Promise<AuthResponse> => {
// const { data: user, error: userError } = await supabase
// .from('users')
// .select(
// `
// id,
// email,
// password_hash,
// profiles (
// name,
// avatar_url,
// phone,
// address,
// preferences,
// social_links,
// verification_status,
// last_active
// )
// `
// )
// .eq('email', input.email)
// .single();

// if (userError || !user) {
// throw new Error('Usuario no encontrado');
// }

// const isPasswordValid = await bcrypt.compare(
// input.password,
// user.password_hash
// );
// if (!isPasswordValid) {
// throw new Error('Contraseña incorrecta');
// }

// if (!process.env.JWT_SECRET) {
// throw new Error('JWT_SECRET environment variable is required');
// }

// const token = jwt.sign(
// {
// id: user.id,
// email: user.email,
// },
// process.env.JWT_SECRET,
// {
// expiresIn: '1h',
// }
// );

// const userResponse: AuthUser = {
// id: user.id,
// email: user.email,
// profile: user.profiles as PublicProfile,
// };

// return { token, user: userResponse };
// };

// export const registerUser = async (
// input: RegisterInput
// ): Promise<AuthResponse> => {
// const { data: existingUser } = await supabase
// .from('users')
// .select('email')
// .eq('email', input.email)
// .single();

// if (existingUser) {
// throw new Error('El email ya está registrado');
// }

// const hashedPassword = await bcrypt.hash(input.password, 10);

// const { data: user, error: insertError } = await supabase
// .from('users')
// .insert([
// {
// email: input.email,
// password_hash: hashedPassword,
// name: input.name,
// },
// ])
// .select()
// .single();

// if (insertError || !user) {
// throw new Error('Error al crear usuario');
// }

// if (!process.env.JWT_SECRET) {
// throw new Error('JWT_SECRET environment variable is required');
// }

// const token = jwt.sign(
// {
// id: user.id,
// email: user.email,
// },
// process.env.JWT_SECRET,
// {
// expiresIn: '1h',
// }
// );

// const userResponse: User = {
// id: user.id,
// email: user.email,
// name: user.name,
// };

// return { token, user: userResponse };
// };
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove commented legacy code.

The large block of commented code should be removed to improve code maintainability. Version control preserves the history if this code needs to be referenced later.

🤖 Prompt for AI Agents
In apps/backend/src/services/auth.service.ts between lines 71 and 183, remove
the entire block of commented-out legacy code related to loginUser and
registerUser functions. This will clean up the file and improve maintainability
since the version control system already preserves the code history.

Comment on lines +11 to +13
export const loginUser = async ({ email, password }: { email: string; password: string }) => {
return await supabase.auth.signInWithPassword({ email, password });
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix return type mismatch - loginUser should return AuthResponse.

The function currently returns Supabase's auth response directly, but based on the imported types and usage in controllers, it should return an AuthResponse object.

-export const loginUser = async ({ email, password }: { email: string; password: string }) => {
-  return await supabase.auth.signInWithPassword({ email, password });
-};
+export const loginUser = async ({ email, password }: LoginInput): Promise<AuthResponse> => {
+  const { data, error } = await supabase.auth.signInWithPassword({ email, password });
+
+  if (error || !data.user || !data.session) {
+    console.error('Error al iniciar sesión:', error);
+    throw new Error('Error al iniciar sesión');
+  }
+
+  // Fetch user profile
+  const { data: profile, error: profileError } = await supabase
+    .from('profiles')
+    .select('*')
+    .eq('user_id', data.user.id)
+    .single();
+
+  if (profileError || !profile) {
+    console.error('Error al obtener perfil:', profileError);
+    throw new Error('Error al obtener perfil de usuario');
+  }
+
+  return {
+    token: data.session.access_token,
+    user: {
+      id: data.user.id,
+      email: data.user.email!,
+      profile: profile as PublicProfile,
+    },
+  };
+};
🤖 Prompt for AI Agents
In apps/backend/src/services/auth.service.ts around lines 11 to 13, the
loginUser function currently returns the raw Supabase auth response, causing a
return type mismatch. Modify the function to explicitly return an AuthResponse
object by mapping or transforming the Supabase response to match the
AuthResponse type expected by the controllers and imported types.

Comment on lines +51 to 68
// Optional: you can create a JWT here if needed
return {
token: data.session?.access_token ?? '',
user: {
id: userId,
email,
profile: {
name,
avatar_url,
phone,
address,
preferences,
social_links,
verification_status: 'unverified',
last_active: new Date().toISOString(),
},
},
process.env.JWT_SECRET,
{
expiresIn: '1h',
}
);

const userResponse: User = {
id: user.id,
email: user.email,
name: user.name,
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve token handling and ensure data consistency.

The current implementation has two issues:

  1. Using an empty string as fallback for missing token could cause authentication failures
  2. Manually constructing the profile object instead of fetching from database may lead to inconsistencies
-  // Optional: you can create a JWT here if needed
+  if (!data.session?.access_token) {
+    throw new Error('No se pudo obtener el token de autenticación');
+  }
+
+  // Fetch the created profile to ensure consistency
+  const { data: profile, error: profileError } = await supabase
+    .from('profiles')
+    .select('*')
+    .eq('user_id', userId)
+    .single();
+
+  if (profileError || !profile) {
+    throw new Error('Error al obtener el perfil creado');
+  }
+
   return {
-    token: data.session?.access_token ?? '',
+    token: data.session.access_token,
     user: {
       id: userId,
       email,
-      profile: {
-        name,
-        avatar_url,
-        phone,
-        address,
-        preferences,
-        social_links,
-        verification_status: 'unverified',
-        last_active: new Date().toISOString(),
-      },
+      profile: profile as PublicProfile,
     },
   };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Optional: you can create a JWT here if needed
return {
token: data.session?.access_token ?? '',
user: {
id: userId,
email,
profile: {
name,
avatar_url,
phone,
address,
preferences,
social_links,
verification_status: 'unverified',
last_active: new Date().toISOString(),
},
},
process.env.JWT_SECRET,
{
expiresIn: '1h',
}
);
const userResponse: User = {
id: user.id,
email: user.email,
name: user.name,
};
if (!data.session?.access_token) {
throw new Error('No se pudo obtener el token de autenticación');
}
// Fetch the created profile to ensure consistency
const { data: profile, error: profileError } = await supabase
.from('profiles')
.select('*')
.eq('user_id', userId)
.single();
if (profileError || !profile) {
throw new Error('Error al obtener el perfil creado');
}
return {
token: data.session.access_token,
user: {
id: userId,
email,
profile: profile as PublicProfile,
},
};
🤖 Prompt for AI Agents
In apps/backend/src/services/auth.service.ts around lines 51 to 68, avoid
returning an empty string as a fallback for the token to prevent authentication
failures; instead, handle the absence of the token explicitly, such as throwing
an error or returning null. Also, replace the manual construction of the user
profile object with a proper fetch from the database to ensure data consistency
and accuracy.

Copy link
Contributor

@respp respp left a comment

Choose a reason for hiding this comment

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

Hi @bernardev254, thanks for your contribution

I wasn't able to run the database to verify that the endpoints are working correctly, since the file src/db/init.ts has some issues. Because of that, I kindly ask you to attach screenshots or example responses so I can see what the endpoints return.

At first glance, the code looks very well implemented. There are just a few things to address before I can merge:

Update setup.sql
To ensure other contributors can run the database properly, you'll need to create the profiles table and configure the storage buckets.

Update the README
If you made changes that affect the initial setup, please update the README.md located inside the /database directory.

Add missing tests
There are some missing tests to cover the functionality you added.

Once that's done, I'll review it again and merge the code.
Thanks again!

@respp
Copy link
Contributor

respp commented Jun 4, 2025

Hi @bernardev254, thanks for your contribution

I wasn't able to run the database to verify that the endpoints are working correctly, since the file src/db/init.ts has some issues. Because of that, I kindly ask you to attach screenshots or example responses so I can see what the endpoints return.

At first glance, the code looks very well implemented. There are just a few things to address before I can merge:

Update setup.sql To ensure other contributors can run the database properly, you'll need to create the profiles table and configure the storage buckets.

Update the README If you made changes that affect the initial setup, please update the README.md located inside the /database directory.

Add missing tests There are some missing tests to cover the functionality you added.

Once that's done, I'll review it again and merge the code. Thanks again!

Also, make sure to address the changes suggested by Coderabbit to avoid technical debt. Thanks

@bernardev254
Copy link
Contributor Author

Hi @bernardev254, thanks for your contribution
I wasn't able to run the database to verify that the endpoints are working correctly, since the file src/db/init.ts has some issues. Because of that, I kindly ask you to attach screenshots or example responses so I can see what the endpoints return.
At first glance, the code looks very well implemented. There are just a few things to address before I can merge:
Update setup.sql To ensure other contributors can run the database properly, you'll need to create the profiles table and configure the storage buckets.
Update the README If you made changes that affect the initial setup, please update the README.md located inside the /database directory.
Add missing tests There are some missing tests to cover the functionality you added.
Once that's done, I'll review it again and merge the code. Thanks again!

Also, make sure to address the changes suggested by Coderabbit to avoid technical debt. Thanks

Hi @bernardev254, thanks for your contribution

I wasn't able to run the database to verify that the endpoints are working correctly, since the file src/db/init.ts has some issues. Because of that, I kindly ask you to attach screenshots or example responses so I can see what the endpoints return.

At first glance, the code looks very well implemented. There are just a few things to address before I can merge:

Update setup.sql To ensure other contributors can run the database properly, you'll need to create the profiles table and configure the storage buckets.

Update the README If you made changes that affect the initial setup, please update the README.md located inside the /database directory.

Add missing tests There are some missing tests to cover the functionality you added.

Once that's done, I'll review it again and merge the code. Thanks again!

thanks for the update..i have realised that my branch has diverged too much after creating a new branch and cherry picked prevoius commits.now my local repo does not even contain the database folder.
i will be creating an clean branch and pr soon

@respp
Copy link
Contributor

respp commented Jun 8, 2025

Hi @bernardev254, thanks for your contribution
I wasn't able to run the database to verify that the endpoints are working correctly, since the file src/db/init.ts has some issues. Because of that, I kindly ask you to attach screenshots or example responses so I can see what the endpoints return.
At first glance, the code looks very well implemented. There are just a few things to address before I can merge:
Update setup.sql To ensure other contributors can run the database properly, you'll need to create the profiles table and configure the storage buckets.
Update the README If you made changes that affect the initial setup, please update the README.md located inside the /database directory.
Add missing tests There are some missing tests to cover the functionality you added.
Once that's done, I'll review it again and merge the code. Thanks again!

Also, make sure to address the changes suggested by Coderabbit to avoid technical debt. Thanks

Hi @bernardev254, thanks for your contribution
I wasn't able to run the database to verify that the endpoints are working correctly, since the file src/db/init.ts has some issues. Because of that, I kindly ask you to attach screenshots or example responses so I can see what the endpoints return.
At first glance, the code looks very well implemented. There are just a few things to address before I can merge:
Update setup.sql To ensure other contributors can run the database properly, you'll need to create the profiles table and configure the storage buckets.
Update the README If you made changes that affect the initial setup, please update the README.md located inside the /database directory.
Add missing tests There are some missing tests to cover the functionality you added.
Once that's done, I'll review it again and merge the code. Thanks again!

thanks for the update..i have realised that my branch has diverged too much after creating a new branch and cherry picked prevoius commits.now my local repo does not even contain the database folder. i will be creating an clean branch and pr soon

Hi @bernardev254, thanks for the quick update and for letting me know!

That makes perfect sense. Starting fresh with a clean branch sounds like a good plan — it’ll help avoid any confusion from the diverged history and missing files.

Once you open the new PR, feel free to tag me again and I’ll be happy to review it. Let me know if you need any help during the process.

Thanks again for your contribution!

@bernardev254
Copy link
Contributor Author

closing this pr in preference of #72

@bernardev254 bernardev254 deleted the profile-management-clean branch June 11, 2025 06:05
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.

2 participants