feat(profile): implement user profile system#60
feat(profile): implement user profile system#60bernardev254 wants to merge 45 commits intoStellar-Rent:mainfrom
Conversation
|
Warning Rate limit exceeded@bernardev254 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 8 minutes and 34 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
""" WalkthroughThis update introduces a comprehensive user profile system on the backend. It adds new routes, controllers, services, middleware, and database schema for managing user profiles, including profile retrieval, update, deletion, and avatar upload. The authentication flow is refactored to use Supabase for user management, and type definitions are expanded to support the extended profile structure. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant API
participant AuthService
participant ProfileService
participant Supabase
Client->>API: POST /auth/register
API->>AuthService: registerUser(data)
AuthService->>Supabase: signUp(email, password)
Supabase-->>AuthService: userId
AuthService->>Supabase: upsert profile (userId, profile fields)
Supabase-->>AuthService: profile
AuthService-->>API: token, user
API-->>Client: 201 Created (token, user)
Client->>API: GET /profile
API->>ProfileService: getUserProfile(userId)
ProfileService->>Supabase: fetch profile by userId
Supabase-->>ProfileService: profile
ProfileService-->>API: profile
API-->>Client: 200 OK (profile)
Client->>API: PATCH /profile
API->>ProfileService: updateUserProfile(userId, updates)
ProfileService->>Supabase: update profile
Supabase-->>ProfileService: updated profile
ProfileService-->>API: updated profile
API-->>Client: 200 OK (updated profile)
Client->>API: POST /profile/avatar
API->>ProfileService: uploadUserAvatar(userId, file)
ProfileService->>Supabase: upload file to storage
Supabase-->>ProfileService: public URL
ProfileService->>Supabase: update profile avatar_url
Supabase-->>ProfileService: updated profile
ProfileService-->>API: avatar_url
API-->>Client: 200 OK (avatar_url)
Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Possibly related PRs
Poem
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 19
🧹 Nitpick comments (6)
apps/backend/.env.example (1)
5-6: Important: Secure these sensitive environment variables.The new Supabase environment variables are correctly added. However, ensure that:
SUPABASE_SERVICE_ROLE_KEYhas elevated privileges and should be kept strictly confidentialSUPABASE_DB_URLshould use proper authentication and connection pooling in production- These values should never be committed to version control
Consider adding comments in the
.env.examplefile to document the purpose of each variable.JWT_SECRET=xyz +# Supabase service role key (admin privileges - keep secure!) SUPABASE_SERVICE_ROLE_KEY=supabase_service_role_key +# Direct database connection URL SUPABASE_DB_URL=postgresqlapps/backend/src/index.ts (1)
55-59: Consider error handling for database initialization.The database initialization is properly awaited before starting the server, which is good practice. However, consider adding error handling to gracefully handle initialization failures.
// 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 start server:', error); + process.exit(1); + });apps/backend/src/types/userProfile.ts (2)
23-23: Consider Date serialization implications.The
Datetype forlast_activemay cause issues during JSON serialization/deserialization. Consider using ISO string representation or timestamp number for better API compatibility.- last_active?: Date; + last_active?: string; // ISO date stringOr add a comment to clarify expected format:
- last_active?: Date; + last_active?: Date; // Will be serialized as ISO string in JSON
2-5: Consider adding validation constraints documentation.While the interface provides type safety, consider documenting validation requirements for fields like email format, phone number format, and URL validation for social links.
Add JSDoc comments with validation requirements:
export interface UserProfileUpdate { + /** Email address - must be valid email format */ email?: string; name?: string; + /** Avatar URL - must be valid HTTPS URL */ avatar_url?: string; + /** Phone number - international format recommended */ phone?: string;apps/backend/src/config/supabase.ts (1)
29-30: Consider making verification_status enum more explicit.The verification status type is correctly defined, but consider extracting it as a separate type for reusability across the codebase.
+export type VerificationStatus = 'unverified' | 'pending' | 'verified'; + export type Database = { public: { Tables: { profiles: { Row: { user_id: 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'; + verification_status: VerificationStatus; last_active: string; // store as ISO string };apps/backend/src/services/auth.service.ts (1)
71-183: Remove commented-out code.Large blocks of commented code reduce readability. If this code needs to be referenced, it's available in version control history.
-// 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 }; -// };
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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 (7)
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/services/a.ts (2)
apps/backend/src/types/userProfile.ts (1)
UserProfileUpdate(1-24)apps/backend/src/config/supabase.ts (1)
supabase(49-61)
apps/backend/src/middleware/auth.middleware.ts (1)
apps/backend/src/config/supabase.ts (1)
supabase(49-61)
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/controllers/auth.controller.ts (1)
apps/backend/src/services/auth.service.ts (2)
registerUser(15-69)loginUser(11-13)
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)
🔇 Additional comments (13)
apps/backend/.eslintrc.json (1)
2-17: LGTM! Clean formatting improvements.The ESLint configuration formatting has been standardized with consistent indentation and proper JSON structure. The rules and configuration remain unchanged and appropriate for a TypeScript project.
apps/backend/src/routes/auth.ts (2)
2-2: Good refactoring: Improved import path consistency.The updated import path follows better file naming conventions with the
.controllersuffix.
5-10: Excellent naming improvement.Renaming from generic
routerto descriptiveauthRouterimproves code readability and makes the purpose clearer, especially when this router is imported and used elsewhere.apps/backend/src/routes/index.ts (1)
1-11: LGTM! Clean routing structure with proper organization.The central routing hub approach is well-implemented with clear path prefixes and helpful comments. This provides good separation of concerns between auth and profile functionality.
apps/backend/src/validators/auth.validator.ts (1)
5-5: Good formatting improvement for function signatures.Converting to single-line function signatures improves readability while maintaining all the validation logic and error handling.
Also applies to: 20-20
apps/backend/src/types/express/index.d.ts (2)
7-7: Good addition for file upload support.The
file?: Express.Multer.Fileproperty correctly supports the avatar upload functionality mentioned in the PR objectives.
6-6:Details
❌ Incorrect review comment
Clarify User type to avoid potential conflicts.
There's a potential type conflict. This file imports
Userfrom@supabase/supabase-js, but there's also a localUserinterface defined inapps/backend/src/types/auth.types.ts(lines 11-15). Ensure consistent usage throughout the codebase.Consider either:
- Using the Supabase
Usertype consistently across the application- Or using the local
Usertype and importing it from the local typesLet me verify which User type is being used in other files:
🏁 Script executed:
#!/bin/bash # Search for User type imports and usage to identify potential conflicts rg -A 2 -B 2 "import.*User.*from" rg -A 2 -B 2 "user\?\:" --type tsLength of output: 1510
No User type conflicts detected
I checked the codebase and confirmed that only the Supabase
Usertype is ever imported (inapps/backend/src/types/express/index.d.ts). The localUserinterface you have inapps/backend/src/types/auth.types.tsisn’t imported or used anywhere else, so there’s no collision at compile time. You can safely ignore the original warning about conflictingUsertypes—or, if the local type is no longer needed, consider renaming or removing it for clarity.Likely an incorrect or invalid review comment.
apps/backend/src/middleware/auth.middleware.ts (1)
4-25: LGTM! Clean refactoring to Supabase authentication.The migration from manual JWT verification to Supabase's
getUsermethod is well-implemented. The middleware correctly:
- Extracts the Bearer token
- Validates the token with Supabase
- Handles errors appropriately
- Attaches the user to the request for downstream use
The async/await pattern and error handling are properly implemented.
apps/backend/src/routes/profile.routes.ts (1)
13-16: Well-structured profile routes with proper authentication.The route definitions follow REST conventions and are properly secured:
- GET for retrieval, PATCH for updates, DELETE for removal
- All routes protected with
authenticateTokenmiddleware- Avatar upload correctly uses multer for file handling
apps/backend/src/types/userProfile.ts (1)
1-24: Well-designed interface with comprehensive profile fields.The
UserProfileUpdateinterface provides a solid foundation for profile management:
- Optional fields enable partial updates
- Nested objects create logical groupings
- String literal types for
verification_statusensure type safety- Comprehensive coverage of profile data
apps/backend/src/db/init.ts (1)
12-24:Details
❓ Verification inconclusive
Verify foreign key reference and add schema validation.
The table creation assumes
auth.usersexists. This could fail if Supabase auth schema isn't properly set up. Consider adding a check or handling this dependency.
🏁 Script executed:
#!/bin/bash # Verify if auth.users table exists in Supabase schema and check for any existing profiles table structure rg -A 10 "auth\.users" --type ts ast-grep --pattern 'CREATE TABLE $_ auth.users'Length of output: 808
Ensure auth.users table exists before creating profiles
Confirm that the
auth.userstable (usually provisioned by Supabase Auth) is available when this migration runs. If you depend on Supabase’s default auth schema, document this requirement or add a pre-migration check. Otherwise, consider a dedicated migration to create or validateauth.usersbefore referencing it.• File:
apps/backend/src/db/init.ts
Lines: 12–24 (foreign key reference toauth.users(id))await client.query(` CREATE TABLE IF NOT EXISTS public.profiles ( user_id uuid PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE, name TEXT NOT NULL, avatar_url TEXT, phone TEXT, address JSONB, preferences JSONB, social_links JSONB, verification_status TEXT CHECK (verification_status IN ('unverified', 'pending', 'verified')) DEFAULT 'unverified', last_active TIMESTAMPTZ DEFAULT now() ); `);apps/backend/src/config/supabase.ts (1)
7-36: Excellent schema design with comprehensive type safety.The migration from
userstoprofilestable with expanded structure is well-designed. The nested objects for address, preferences, and social_links provide good organization, and the TypeScript types properly handle Insert/Update operations.apps/backend/src/types/auth.types.ts (1)
60-64: Good interface design for AuthUser.The
AuthUserinterface properly combines user identification with profile data, providing a clean separation of concerns.
| import multer from 'multer'; | ||
|
|
||
| const storage = multer.memoryStorage(); // store in memory before upload to Supabase | ||
| export const upload = multer({ storage }); |
There was a problem hiding this comment.
Critical: Add security configurations to prevent vulnerabilities.
The current multer configuration lacks essential security measures that could lead to serious vulnerabilities:
- No file size limits - Attackers could upload large files to exhaust server memory
- No file type restrictions - Any file type can be uploaded
- No upload limits - Multiple large uploads could crash the server
Apply this diff to add essential security configurations:
import multer from 'multer';
const storage = multer.memoryStorage(); // store in memory before upload to Supabase
-export const upload = multer({ storage });
+export const upload = multer({
+ storage,
+ limits: {
+ fileSize: 5 * 1024 * 1024, // 5MB limit
+ files: 1 // Only allow 1 file per request
+ },
+ 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'));
+ }
+ }
+});📝 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.
| import multer from 'multer'; | |
| const storage = multer.memoryStorage(); // store in memory before upload to Supabase | |
| export const upload = multer({ storage }); | |
| import multer from 'multer'; | |
| const storage = multer.memoryStorage(); // store in memory before upload to Supabase | |
| export const upload = multer({ | |
| storage, | |
| limits: { | |
| fileSize: 5 * 1024 * 1024, // 5MB limit | |
| files: 1 // Only allow 1 file per request | |
| }, | |
| 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 lines 1 to 4, the multer setup lacks
security configurations such as file size limits, file type restrictions, and
upload limits. To fix this, update the multer configuration to include a file
size limit (e.g., max file size in bytes), restrict accepted file types using a
fileFilter function that checks MIME types, and limit the number of files or
fields accepted per request. This will prevent large or malicious uploads from
exhausting server resources or causing crashes.
| 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 }; | ||
| }; |
There was a problem hiding this comment.
Fix critical import issue and improve file naming.
Several issues need to be addressed:
- Missing import: The
supabaseclient is used but not imported, causing a compilation error. - Poor file naming:
a.tsis not descriptive. Consider renaming toprofile.service.ts. - Missing input validation: The
userIdparameter should be validated before use.
Add the missing import at the top of the file:
+import { supabase } from '../config/supabase';
import type { UserProfileUpdate } from '../types/userProfile';Consider adding input validation:
export const updateUserProfile = async (userId: string, updates: UserProfileUpdate) => {
+ if (!userId || typeof userId !== 'string') {
+ return { error: { message: 'Invalid user ID provided' } };
+ }
+
const { data, error } = await supabase📝 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.
| 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) => { | |
| if (!userId || typeof userId !== 'string') { | |
| return { error: { message: 'Invalid user ID provided' } }; | |
| } | |
| 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, the supabase client is used but
not imported, causing a compilation error; add the appropriate import statement
for supabase at the top of the file. Rename the file from a.ts to
profile.service.ts to improve clarity and maintainability. Additionally, add
input validation for the userId parameter at the start of the updateUserProfile
function to ensure it is a non-empty string before proceeding with the database
update.
| import routes from './routes'; | ||
| import authRouter from './routes/auth'; | ||
| import profileRouter from './routes/profile.routes'; |
There was a problem hiding this comment.
Fix inconsistent router imports and usage.
The code imports both the consolidated routes from ./routes and individual routers (authRouter, profileRouter), but only uses the consolidated routes on line 44. This creates unused imports and suggests incomplete refactoring.
Remove the unused individual router imports:
import routes from './routes';
-import authRouter from './routes/auth';
-import profileRouter from './routes/profile.routes';📝 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.
| import routes from './routes'; | |
| import authRouter from './routes/auth'; | |
| import profileRouter from './routes/profile.routes'; | |
| import routes from './routes'; |
🤖 Prompt for AI Agents
In apps/backend/src/index.ts around lines 10 to 12, the imports for authRouter
and profileRouter are unused because only the consolidated routes import is used
later. Remove the individual router imports for authRouter and profileRouter to
clean up unused code and complete the refactoring.
| const router = Router(); | ||
|
|
||
| // Apply prefixes here | ||
| router.use('/auth', authRouter); | ||
| router.use('/profile', profileRouter); |
There was a problem hiding this comment.
Remove redundant router construction.
Lines 27-31 create a new router and mount individual routers, but this router is never used since line 44 uses the consolidated routes instead. This dead code should be removed.
Remove the unused router construction:
-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.
| 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 31, the code creates a new
router and mounts individual routers on it, but this router is never used later
since the consolidated `routes` router is used instead. Remove the entire block
that constructs and uses this unused router to eliminate dead code and avoid
confusion.
| // Step 1: Supabase Auth registration | ||
| const { data, error } = await supabase.auth.signUp({ email, password }); | ||
|
|
||
| if (!process.env.JWT_SECRET) { | ||
| throw new Error('JWT_SECRET environment variable is required'); | ||
| if (error || !data.user) { | ||
| console.error('Error al registrar usuario:', error); | ||
| throw new Error('Error al registrar usuario'); | ||
| } | ||
|
|
||
| const token = jwt.sign( | ||
| { | ||
| id: user.id, | ||
| email: user.email, | ||
| }, | ||
| process.env.JWT_SECRET, | ||
| { | ||
| expiresIn: '1h', | ||
| } | ||
| ); | ||
| const userId = data.user.id; | ||
|
|
||
| const userResponse: User = { | ||
| id: user.id, | ||
| email: user.email, | ||
| name: user.name, | ||
| }; | ||
|
|
||
| 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([ | ||
| // Step 2: Insert into profiles | ||
| const { error: profileError } = await supabase.from('profiles').upsert( | ||
| [ | ||
| { | ||
| email: input.email, | ||
| password_hash: hashedPassword, | ||
| name: input.name, | ||
| user_id: userId, | ||
| name, | ||
| avatar_url, | ||
| phone, | ||
| address, | ||
| preferences, | ||
| social_links, | ||
| verification_status: 'unverified', | ||
| last_active: new Date().toISOString(), | ||
| }, | ||
| ]) | ||
| .select() | ||
| .single(); | ||
|
|
||
| if (insertError || !user) { | ||
| throw new Error('Error al crear usuario'); | ||
| } | ||
| ], | ||
| { onConflict: 'user_id' } | ||
| ); | ||
|
|
||
| if (!process.env.JWT_SECRET) { | ||
| throw new Error('JWT_SECRET environment variable is required'); | ||
| if (profileError) { | ||
| console.error('Error al crear perfil de usuario:', profileError); | ||
| throw new Error('Error al crear perfil de usuario'); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Consider using a transaction for atomic user registration.
The current implementation creates a user in Supabase Auth and then separately creates a profile. If profile creation fails, you'll have an orphaned auth user without a profile.
Consider wrapping both operations in a transaction or implementing rollback logic:
export const registerUser = async (input: RegisterInput): Promise<AuthResponse> => {
const { email, password, name, avatar_url, phone, address, preferences, social_links } = input;
// Step 1: Supabase Auth registration
const { data, error } = await supabase.auth.signUp({ email, password });
if (error || !data.user) {
console.error('Error al registrar usuario:', error);
throw new Error('Error al registrar usuario');
}
const userId = data.user.id;
// Step 2: Insert into profiles
- const { error: profileError } = await supabase.from('profiles').upsert(
+ const { error: profileError } = await supabase.from('profiles').insert(
[
{
user_id: userId,
name,
avatar_url,
phone,
address,
preferences,
social_links,
verification_status: 'unverified',
last_active: new Date().toISOString(),
},
],
- { onConflict: 'user_id' }
);
if (profileError) {
console.error('Error al crear perfil de usuario:', profileError);
+ // Consider deleting the auth user if profile creation fails
+ await supabase.auth.admin.deleteUser(userId);
throw new Error('Error al crear perfil de usuario');
}Also, using insert instead of upsert ensures we don't accidentally overwrite existing profiles.
📝 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.
| // Step 1: Supabase Auth registration | |
| const { data, error } = await supabase.auth.signUp({ email, password }); | |
| if (!process.env.JWT_SECRET) { | |
| throw new Error('JWT_SECRET environment variable is required'); | |
| if (error || !data.user) { | |
| console.error('Error al registrar usuario:', error); | |
| throw new Error('Error al registrar usuario'); | |
| } | |
| const token = jwt.sign( | |
| { | |
| id: user.id, | |
| email: user.email, | |
| }, | |
| process.env.JWT_SECRET, | |
| { | |
| expiresIn: '1h', | |
| } | |
| ); | |
| const userId = data.user.id; | |
| const userResponse: User = { | |
| id: user.id, | |
| email: user.email, | |
| name: user.name, | |
| }; | |
| 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([ | |
| // Step 2: Insert into profiles | |
| const { error: profileError } = await supabase.from('profiles').upsert( | |
| [ | |
| { | |
| email: input.email, | |
| password_hash: hashedPassword, | |
| name: input.name, | |
| user_id: userId, | |
| name, | |
| avatar_url, | |
| phone, | |
| address, | |
| preferences, | |
| social_links, | |
| verification_status: 'unverified', | |
| last_active: new Date().toISOString(), | |
| }, | |
| ]) | |
| .select() | |
| .single(); | |
| if (insertError || !user) { | |
| throw new Error('Error al crear usuario'); | |
| } | |
| ], | |
| { onConflict: 'user_id' } | |
| ); | |
| if (!process.env.JWT_SECRET) { | |
| throw new Error('JWT_SECRET environment variable is required'); | |
| if (profileError) { | |
| console.error('Error al crear perfil de usuario:', profileError); | |
| throw new Error('Error al crear perfil de usuario'); | |
| } | |
| // Step 1: Supabase Auth registration | |
| const { data, error } = await supabase.auth.signUp({ email, password }); | |
| if (error || !data.user) { | |
| console.error('Error al registrar usuario:', error); | |
| throw new Error('Error al registrar usuario'); | |
| } | |
| const userId = data.user.id; | |
| // Step 2: Insert into profiles | |
| const { error: profileError } = await supabase.from('profiles').insert( | |
| [ | |
| { | |
| user_id: userId, | |
| name, | |
| avatar_url, | |
| phone, | |
| address, | |
| preferences, | |
| social_links, | |
| verification_status: 'unverified', | |
| last_active: new Date().toISOString(), | |
| }, | |
| ] | |
| ); | |
| if (profileError) { | |
| console.error('Error al crear perfil de usuario:', profileError); | |
| // Consider deleting the auth user if profile creation fails | |
| await supabase.auth.admin.deleteUser(userId); | |
| throw new Error('Error al crear perfil de usuario'); | |
| } |
🤖 Prompt for AI Agents
In apps/backend/src/services/auth.service.ts between lines 18 and 49, the user
registration process creates a Supabase Auth user and then inserts or updates
the profile separately, risking orphaned users if profile creation fails. To fix
this, implement a transaction or rollback mechanism that ensures both user
creation and profile insertion succeed or both fail together. Replace the upsert
with an insert to avoid overwriting existing profiles, and handle errors to
rollback the auth user creation if profile insertion fails.
| export const updateProfile = async (req: Request, res: Response) => { | ||
| if (!req.user) return res.status(401).json({ error: 'Usuario no autenticado' }); | ||
|
|
||
| const result = await updateUserProfile(req.user.id, req.body); | ||
| if (result.error) return res.status(400).json({ error: result.error.message }); | ||
|
|
||
| res.json(result.profile); | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add input validation for profile updates.
Passing req.body directly to the service without validation is a security risk. Users could potentially update fields they shouldn't have access to.
Apply this diff to add input validation:
export const updateProfile = async (req: Request, res: Response) => {
if (!req.user) return res.status(401).json({ error: 'Usuario no autenticado' });
- const result = await updateUserProfile(req.user.id, req.body);
+ // Validate and sanitize input
+ const allowedFields = ['name', 'avatar_url', 'phone', 'address', 'preferences', 'social_links'];
+ const updates: any = {};
+
+ for (const field of allowedFields) {
+ if (req.body[field] !== undefined) {
+ updates[field] = req.body[field];
+ }
+ }
+
+ const result = await updateUserProfile(req.user.id, updates);
if (result.error) return res.status(400).json({ error: result.error.message });
res.json(result.profile);
};Consider also adding schema validation using a library like Joi or Zod for more robust validation.
📝 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.
| export const updateProfile = async (req: Request, res: Response) => { | |
| if (!req.user) return res.status(401).json({ error: 'Usuario no autenticado' }); | |
| const result = await updateUserProfile(req.user.id, req.body); | |
| if (result.error) return res.status(400).json({ error: result.error.message }); | |
| res.json(result.profile); | |
| }; | |
| export const updateProfile = async (req: Request, res: Response) => { | |
| if (!req.user) return res.status(401).json({ error: 'Usuario no autenticado' }); | |
| // Validate and sanitize input | |
| const allowedFields = ['name', 'avatar_url', 'phone', 'address', 'preferences', 'social_links']; | |
| const updates: any = {}; | |
| for (const field of allowedFields) { | |
| if (req.body[field] !== undefined) { | |
| updates[field] = req.body[field]; | |
| } | |
| } | |
| const result = await updateUserProfile(req.user.id, updates); | |
| if (result.error) return res.status(400).json({ error: result.error.message }); | |
| res.json(result.profile); | |
| }; |
🤖 Prompt for AI Agents
In apps/backend/src/controllers/profile.controller.ts around lines 18 to 25, the
updateProfile function passes req.body directly to updateUserProfile without
validating the input, which is a security risk. To fix this, add input
validation before calling updateUserProfile by defining a whitelist of allowed
fields or using a validation schema with a library like Joi or Zod. Validate
req.body against this schema and return a 400 error response if validation
fails, ensuring only permitted fields are processed.
| 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' }); | ||
| }; |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Consider deleting the auth user when deleting an account.
The current implementation only deletes the profile but not the associated Supabase auth user, which could lead to orphaned auth records.
Consider updating the service to also delete the auth user:
// In profile.service.ts
export const deleteUserAccount = async (userId: string) => {
// Delete profile
const { error: profileError } = await supabase.from('profiles').delete().eq('user_id', userId);
if (profileError) return { error: profileError };
// Delete auth user
const { error: authError } = await supabase.auth.admin.deleteUser(userId);
if (authError) return { error: authError };
return { success: true };
};🏁 Script executed:
#!/bin/bash
# Description: Check if there's a cascade delete or if auth users are handled separately
# Search for any auth user deletion logic
rg -A 5 "deleteUser|auth.*delete|delete.*auth" --type ts
# Check if there's a database trigger or RLS policy for cascade deletion
fd -e sql | xargs rg -l "CASCADE DELETE|ON DELETE CASCADE" 2>/dev/null || echo "No SQL files found"Length of output: 1964
Ensure Supabase auth user is deleted when removing the profile
The current deleteUserAccount implementation only deletes the row from the profiles table, leaving behind an orphaned Supabase auth user.
Please update in apps/backend/src/services/profile.service.ts:
- Augment
deleteUserAccountto also callsupabase.auth.admin.deleteUser(userId)using your service‐role key. - Handle any errors from the auth deletion before returning success.
Suggested change:
export const deleteUserAccount = async (userId: string) => {
// Delete profile
const { error: profileError } = await supabase
.from('profiles')
.delete()
.eq('user_id', userId);
if (profileError) return { error: profileError };
+ // Delete corresponding Supabase auth user
+ const { error: authError } = await supabase.auth.admin.deleteUser(userId);
+ if (authError) return { error: authError };
return { success: true };
};📝 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.
| 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' }); | |
| }; | |
| export const deleteUserAccount = async (userId: string) => { | |
| // Delete profile | |
| const { error: profileError } = await supabase | |
| .from('profiles') | |
| .delete() | |
| .eq('user_id', userId); | |
| if (profileError) return { error: profileError }; | |
| // Delete corresponding Supabase auth user | |
| const { error: authError } = await supabase.auth.admin.deleteUser(userId); | |
| if (authError) return { error: authError }; | |
| return { success: true }; | |
| }; |
🤖 Prompt for AI Agents
In apps/backend/src/services/profile.service.ts around the deleteUserAccount
function, the current code only deletes the user profile from the database but
does not remove the associated Supabase auth user, causing orphaned auth
records. Update deleteUserAccount to first delete the profile row, then call
supabase.auth.admin.deleteUser(userId) to delete the auth user using the
service-role key. Handle any errors from the auth deletion and return them
appropriately before returning success.
| export const getUserProfile = async (userId: string) => { | ||
| const { data, error } = await supabase.from('profiles').select('*').eq('user_id', userId); | ||
|
|
||
| return error ? { error } : { profile: data }; | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Use explicit field selection instead of select('*').
Using select('*') could potentially expose sensitive or internal fields that shouldn't be returned to the client.
export const getUserProfile = async (userId: string) => {
- const { data, error } = await supabase.from('profiles').select('*').eq('user_id', userId);
+ const { data, error } = await supabase
+ .from('profiles')
+ .select('user_id, name, avatar_url, phone, address, preferences, social_links, verification_status, last_active, created_at')
+ .eq('user_id', userId);
return error ? { error } : { profile: data };
};This ensures only intended fields are exposed to the client.
📝 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.
| export const getUserProfile = async (userId: string) => { | |
| const { data, error } = await supabase.from('profiles').select('*').eq('user_id', userId); | |
| return error ? { error } : { profile: data }; | |
| }; | |
| export const getUserProfile = async (userId: string) => { | |
| const { data, error } = await supabase | |
| .from('profiles') | |
| .select('user_id, name, avatar_url, phone, address, preferences, social_links, verification_status, last_active, created_at') | |
| .eq('user_id', userId); | |
| return error ? { error } : { profile: data }; | |
| }; |
🤖 Prompt for AI Agents
In apps/backend/src/services/profile.service.ts around lines 5 to 9, replace the
use of select('*') with an explicit list of fields to retrieve from the
'profiles' table. Identify and specify only the safe, necessary fields to expose
in the select method to avoid returning sensitive or internal data to the
client.
| export const uploadUserAvatar = async (userId: string, req: Request) => { | ||
| if (!req.file) { | ||
| return { error: new Error('No file uploaded') }; | ||
| } | ||
|
|
||
| const file = req.file; | ||
| const filePath = `avatars/${userId}/${Date.now()}_${file.originalname}`; | ||
|
|
||
| const { error: uploadError } = await supabase.storage | ||
| .from('avatars') | ||
| .upload(filePath, file.buffer, { | ||
| contentType: file.mimetype, | ||
| }); | ||
|
|
||
| if (uploadError) return { error: uploadError }; | ||
|
|
||
| const { data } = supabase.storage.from('avatars').getPublicUrl(filePath); | ||
| const publicUrl = data?.publicUrl; | ||
|
|
||
| if (!publicUrl) return { error: new Error('Failed to generate public URL') }; | ||
|
|
||
| await supabase.from('profiles').update({ avatar_url: publicUrl }).eq('user_id', userId); | ||
|
|
||
| return { avatar_url: publicUrl }; | ||
| }; |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Add file validation and improve error handling for avatar uploads.
The current implementation has several security concerns:
- No file type validation
- No file size limits
file.originalnamecould contain unsafe characters- Missing error handling for profile update
Apply these improvements:
export const uploadUserAvatar = async (userId: string, req: Request) => {
if (!req.file) {
return { error: new Error('No file uploaded') };
}
const file = req.file;
+
+ // Validate file type
+ const allowedMimeTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
+ if (!allowedMimeTypes.includes(file.mimetype)) {
+ return { error: new Error('Invalid file type. Only JPEG, PNG, GIF, and WebP are allowed') };
+ }
+
+ // Validate file size (e.g., 5MB limit)
+ const maxSizeInBytes = 5 * 1024 * 1024;
+ if (file.size > maxSizeInBytes) {
+ return { error: new Error('File size exceeds 5MB limit') };
+ }
+
+ // Sanitize filename
+ const sanitizedFilename = file.originalname.replace(/[^a-zA-Z0-9.-]/g, '_');
- const filePath = `avatars/${userId}/${Date.now()}_${file.originalname}`;
+ const filePath = `avatars/${userId}/${Date.now()}_${sanitizedFilename}`;
const { error: uploadError } = await supabase.storage
.from('avatars')
.upload(filePath, file.buffer, {
contentType: file.mimetype,
});
if (uploadError) return { error: uploadError };
const { data } = supabase.storage.from('avatars').getPublicUrl(filePath);
const publicUrl = data?.publicUrl;
if (!publicUrl) return { error: new Error('Failed to generate public URL') };
- await supabase.from('profiles').update({ avatar_url: publicUrl }).eq('user_id', userId);
+ const { error: updateError } = await supabase
+ .from('profiles')
+ .update({ avatar_url: publicUrl })
+ .eq('user_id', userId);
+
+ if (updateError) {
+ // Consider deleting the uploaded file if profile update fails
+ await supabase.storage.from('avatars').remove([filePath]);
+ return { error: new Error('Failed to update profile with new avatar') };
+ }
return { avatar_url: publicUrl };
};Also ensure that file size limits are configured in your multer middleware.
📝 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.
| export const uploadUserAvatar = async (userId: string, req: Request) => { | |
| if (!req.file) { | |
| return { error: new Error('No file uploaded') }; | |
| } | |
| const file = req.file; | |
| const filePath = `avatars/${userId}/${Date.now()}_${file.originalname}`; | |
| const { error: uploadError } = await supabase.storage | |
| .from('avatars') | |
| .upload(filePath, file.buffer, { | |
| contentType: file.mimetype, | |
| }); | |
| if (uploadError) return { error: uploadError }; | |
| const { data } = supabase.storage.from('avatars').getPublicUrl(filePath); | |
| const publicUrl = data?.publicUrl; | |
| if (!publicUrl) return { error: new Error('Failed to generate public URL') }; | |
| await supabase.from('profiles').update({ avatar_url: publicUrl }).eq('user_id', userId); | |
| return { avatar_url: publicUrl }; | |
| }; | |
| export const uploadUserAvatar = async (userId: string, req: Request) => { | |
| if (!req.file) { | |
| return { error: new Error('No file uploaded') }; | |
| } | |
| const file = req.file; | |
| // Validate file type | |
| const allowedMimeTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']; | |
| if (!allowedMimeTypes.includes(file.mimetype)) { | |
| return { error: new Error('Invalid file type. Only JPEG, PNG, GIF, and WebP are allowed') }; | |
| } | |
| // Validate file size (e.g., 5MB limit) | |
| const maxSizeInBytes = 5 * 1024 * 1024; | |
| if (file.size > maxSizeInBytes) { | |
| return { error: new Error('File size exceeds 5MB limit') }; | |
| } | |
| // Sanitize filename | |
| const sanitizedFilename = file.originalname.replace(/[^a-zA-Z0-9.\-]/g, '_'); | |
| const filePath = `avatars/${userId}/${Date.now()}_${sanitizedFilename}`; | |
| const { error: uploadError } = await supabase.storage | |
| .from('avatars') | |
| .upload(filePath, file.buffer, { | |
| contentType: file.mimetype, | |
| }); | |
| if (uploadError) { | |
| return { error: uploadError }; | |
| } | |
| const { data } = supabase.storage.from('avatars').getPublicUrl(filePath); | |
| const publicUrl = data?.publicUrl; | |
| if (!publicUrl) { | |
| return { error: new Error('Failed to generate public URL') }; | |
| } | |
| const { error: updateError } = await supabase | |
| .from('profiles') | |
| .update({ avatar_url: publicUrl }) | |
| .eq('user_id', userId); | |
| if (updateError) { | |
| // Consider deleting the uploaded file if profile update fails | |
| await supabase.storage.from('avatars').remove([filePath]); | |
| return { error: new Error('Failed to update profile with new avatar') }; | |
| } | |
| return { avatar_url: publicUrl }; | |
| }; |
🤖 Prompt for AI Agents
In apps/backend/src/services/profile.service.ts between lines 26 and 50, add
validation to check the uploaded file's type against allowed image MIME types
and ensure the file size is within acceptable limits (note: configure size
limits in multer middleware). Sanitize file.originalname to remove unsafe
characters before using it in the file path. Add error handling for the profile
update operation by checking the result and returning an error if the update
fails. These changes will improve security and robustness of the avatar upload
process.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
apps/backend/src/index.ts (2)
11-13:⚠️ Potential issueRemove unused router imports.
These individual router imports are still unused as identified in previous reviews. The code only uses the consolidated
routesimport on line 46, making these imports redundant.Apply this diff to remove the unused imports:
import routes from './routes'; -import authRouter from './routes/auth'; -import profileRouter from './routes/profile.routes';
29-33:⚠️ Potential issueRemove redundant router construction.
This router construction is still unused as identified in previous reviews. The router is created and configured but never actually used in the application middleware stack.
Apply this diff to remove the unused router construction:
-const router = Router(); - -// Apply prefixes here -router.use('/auth', authRouter); -router.use('/profile', profileRouter);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/backend/package.json(1 hunks)apps/backend/src/config/supabase.ts(1 hunks)apps/backend/src/index.ts(4 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/backend/package.json
- apps/backend/src/config/supabase.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
apps/backend/src/index.ts (1)
apps/backend/src/db/init.ts (1)
initializeDatabase(4-32)
🔇 Additional comments (2)
apps/backend/src/index.ts (2)
5-5: Good addition for database initialization.The import of
initializeDatabaseis properly used later in the file to ensure the database schema is ready before the server starts.
60-65: Excellent database initialization pattern.The modification to initialize the database before starting the server is a good practice that ensures the schema is ready and prevents potential startup issues.
| app.use(rateLimiter); | ||
|
|
||
| // Routes | ||
| app.use('/api', routes); |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Verify the consolidated routes structure.
The application now uses consolidated routes under the /api prefix. Ensure that the ./routes/index.ts file properly exports and configures all necessary routes including auth and profile routes.
🏁 Script executed:
#!/bin/bash
# Description: Verify the routes structure and exports
# Expected: Find the routes index file and check its exports
echo "=== Checking routes index file ==="
cat apps/backend/src/routes/index.ts
echo -e "\n=== Checking for route files ==="
fd -t f -e ts . apps/backend/src/routes/
echo -e "\n=== Checking route imports in index ==="
rg "import.*from.*routes" apps/backend/src/routes/index.tsLength of output: 918
Missing property routes in consolidated router
The apps/backend/src/routes/index.ts currently only mounts the auth and profile routers, but there’s also a property.route.ts under apps/backend/src/routes/ that isn’t exposed. Please update index.ts to import and mount it:
• File: apps/backend/src/routes/index.ts
- Add:
import propertyRouter from './property.route';
- Add:
router.use('/property', propertyRouter);
• Verify that apps/backend/src/routes/property.route.ts exports a default Express Router.
🤖 Prompt for AI Agents
In apps/backend/src/routes/index.ts around line 46, the consolidated router
currently imports and mounts only auth and profile routes but misses the
property routes. To fix this, import the property router from './property.route'
and mount it on the router with the path '/property'. Also, verify that
apps/backend/src/routes/property.route.ts exports a default Express Router to
ensure proper integration.
| // Routes | ||
| app.use('/api', routes); | ||
|
|
||
| app.use('/auth', authRoutes); |
There was a problem hiding this comment.
Fix missing import for authRoutes.
The code references authRoutes on line 48, but this import is not visible in the current code. This will cause a runtime error.
Add the missing import or verify if this line should be removed:
+import authRoutes from './routes/auth.routes';Or if this is redundant with the new consolidated routes, remove this line:
-app.use('/auth', authRoutes);🤖 Prompt for AI Agents
In apps/backend/src/index.ts at line 48, the code uses authRoutes without
importing it, causing a runtime error. To fix this, either add the appropriate
import statement for authRoutes at the top of the file or, if authRoutes is no
longer needed due to route consolidation, remove the line app.use('/auth',
authRoutes) entirely.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
|
Hi @bernardev25 thank you so much for your work on PR #60 and for implementing the profile management system in StellarRent, I value your effort, but I'm having trouble reviewing your specific changes because the PR includes many commits from other contributors like Benjtalkshow and Lynndabel, which makes it a bit confusing for me; would it be possible for you to resubmit this PR from a new branch that only contains your modifications related to the issue, so I can better focus on your contribution? If you need help creating the branch, I’d be happy to guide you, thanks in advance for your collaboration. |
|
I have created a new branch and submitted a new pr.check it out #68 |
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 ensures type safety and improves error handling when interacting with the Supabase backend.
🔗 Related Issues
Closes #44 .
🔄 Changes Made
🖼️ Current Output
Provide visual evidence of the changes:
🧪 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
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:
💬 Comments
Any additional context, questions, or considerations for reviewers.
Summary by CodeRabbit
New Features
Enhancements
Bug Fixes
Chores