@@ -267,6 +267,22 @@ const bestEffortDeleteUploadedObject = async (project, filePath) => {
267267} ;
268268
269269module . exports . createProject = async ( req , res ) => {
270+ const finalizeProjectCreation = ( projectObj , newProject ) => {
271+ markDeveloperOnboardingStep ( req . user . _id , 'projectCreated' , { projectId : newProject . _id } )
272+ . then ( ( ) => {
273+ // Also reset subsequent steps since this is a new project
274+ return Promise . all ( [
275+ markDeveloperOnboardingStep ( req . user . _id , 'collectionCreated' , { _reset : true } ) ,
276+ markDeveloperOnboardingStep ( req . user . _id , 'firstApiCall' , { _reset : true } )
277+ ] ) ;
278+ } )
279+ . catch ( ( err ) => {
280+ console . error ( '[onboarding] Failed to mark projectCreated:' , err . message ) ;
281+ } ) ;
282+ emitEvent ( req . user . _id , 'project_created' , { projectName : projectObj . name } , newProject . _id ) ;
283+ return res . status ( 201 ) . json ( { success : true , data : projectObj , message : "Project created successfully" } ) ;
284+ } ;
285+
270286 const executeOperation = async ( session ) => {
271287 const { name, description, siteUrl, templateId } = createProjectSchema . parse ( req . body ) ;
272288
@@ -307,20 +323,18 @@ module.exports.createProject = async (req, res) => {
307323 const template = PROJECT_TEMPLATES [ templateId ] ;
308324 if ( template . isAuthEnabled ) {
309325 newProject . isAuthEnabled = true ;
310- // The default users collection is appended later or explicitly, let's see.
311- // Wait, does 'users' collection get automatically added if isAuthEnabled is set?
312- // Let's add it explicitly if not present.
313326 }
314327 if ( template . collections && template . collections . length > 0 ) {
315328 newProject . collections = template . collections . map ( col => {
316329 const mode = typeof col . rls === 'string' ? col . rls : ( col . rls ?. mode || 'public-read' ) ;
330+ const defaultRls = getDefaultRlsForCollection ( col . name , col . model ) ;
317331 return {
318332 name : col . name ,
319333 model : col . model ,
320334 rls : {
321335 enabled : mode !== 'public-read' ,
322336 mode,
323- ownerField : col . name === 'users' ? '_id' : 'userId' ,
337+ ownerField : defaultRls . ownerField ,
324338 requireAuthForWrite : true
325339 }
326340 } ;
@@ -364,54 +378,41 @@ module.exports.createProject = async (req, res) => {
364378
365379 await session . commitTransaction ( ) ;
366380 session . endSession ( ) ;
367-
368- markDeveloperOnboardingStep ( req . user . _id , 'projectCreated' , { projectId : newProject . _id } )
369- . then ( ( ) => {
370- // Also reset subsequent steps since this is a new project
371- return Promise . all ( [
372- markDeveloperOnboardingStep ( req . user . _id , 'collectionCreated' , { _reset : true } ) ,
373- markDeveloperOnboardingStep ( req . user . _id , 'firstApiCall' , { _reset : true } )
374- ] ) ;
375- } )
376- . catch ( ( err ) => {
377- console . error ( '[onboarding] Failed to mark projectCreated:' , err . message ) ;
378- } ) ;
379- emitEvent ( req . user . _id , 'project_created' , { projectName : projectObj . name } , newProject . _id ) ;
380- return res . status ( 201 ) . json ( { success : true , data : projectObj , message : "Project created successfully" } ) ;
381+ return finalizeProjectCreation ( projectObj , newProject ) ;
381382 } catch ( err ) {
382383 if ( session ) {
383- try { await session . abortTransaction ( ) ; } catch ( e ) { }
384+ try {
385+ await session . abortTransaction ( ) ;
386+ } catch ( e ) {
387+ console . error ( "Failed to abort transaction:" , e . message ) ;
388+ }
384389 session . endSession ( ) ;
385390 }
386391
387- const isTransactionError = err . message && (
388- err . message . includes ( "Transaction numbers are only allowed" ) ||
389- err . message . includes ( "buffering timed out" ) ||
390- err . message . includes ( "standalone" ) ||
391- err . message . includes ( "replica set" ) ||
392- err . message . includes ( "Session" )
393- ) ;
392+ const isTransactionError = err . message &&
393+ err . message . includes ( "Transaction numbers are only allowed" ) &&
394+ ( err . code === 20 || err . codeName === 'IllegalOperation' ) ;
394395
395396 if ( isTransactionError ) {
396397 try {
397398 const { projectObj, newProject } = await executeOperation ( null ) ;
398- markDeveloperOnboardingStep ( req . user . _id , 'projectCreated' , { projectId : newProject . _id } ) . catch ( ( err ) => {
399- console . error ( '[onboarding] Failed to mark projectCreated:' , err . message ) ;
400- } ) ;
401- emitEvent ( req . user . _id , 'project_created' , { projectName : projectObj . name } , newProject . _id ) ;
402- return res . status ( 201 ) . json ( { success : true , data : projectObj , message : "Project created successfully" } ) ;
399+ return finalizeProjectCreation ( projectObj , newProject ) ;
403400 } catch ( retryErr ) {
404- if ( retryErr instanceof z . ZodError ) return res . status ( 400 ) . json ( { success : false , message : "Validation failed" , error : retryErr . issues } ) ;
405- const statusCode = ( retryErr instanceof AppError ? retryErr . statusCode : null ) || 500 ;
401+ if ( retryErr instanceof z . ZodError ) {
402+ return res . status ( 400 ) . json ( { success : false , data : retryErr . issues , message : "Validation failed" } ) ;
403+ }
404+ const statusCode = retryErr instanceof AppError ? retryErr . statusCode : 500 ;
406405 const message = statusCode === 500 ? "Internal server error" : retryErr . message ;
407- return res . status ( statusCode ) . json ( { success : false , message : message } ) ;
406+ return res . status ( statusCode ) . json ( { success : false , data : { } , message } ) ;
408407 }
409408 }
410409
411- if ( err instanceof z . ZodError ) return res . status ( 400 ) . json ( { success : false , message : "Validation failed" , error : err . issues } ) ;
412- const statusCode = ( err instanceof AppError ? err . statusCode : null ) || 500 ;
410+ if ( err instanceof z . ZodError ) {
411+ return res . status ( 400 ) . json ( { success : false , data : err . issues , message : "Validation failed" } ) ;
412+ }
413+ const statusCode = err instanceof AppError ? err . statusCode : 500 ;
413414 const message = statusCode === 500 ? "Internal server error" : err . message ;
414- return res . status ( statusCode ) . json ( { success : false , message : message } ) ;
415+ return res . status ( statusCode ) . json ( { success : false , data : { } , message } ) ;
415416 }
416417} ;
417418
0 commit comments