From eb516dca8d9014b4218e5752a04d084b1d8cf8be Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Fri, 4 Oct 2024 16:38:13 +0900
Subject: [PATCH 01/28] =?UTF-8?q?feat:=20=EC=9C=A0=EC=A0=80=EA=B0=80=20?=
 =?UTF-8?q?=EB=93=A4=EC=96=B4=EA=B0=84=20=EC=8A=A4=ED=8E=98=EC=9D=B4?=
 =?UTF-8?q?=EC=8A=A4=20=EC=B0=BE=EA=B8=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 nestjs-BE/server/src/users/users.service.ts | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/nestjs-BE/server/src/users/users.service.ts b/nestjs-BE/server/src/users/users.service.ts
index 72f28a0a..e68104eb 100644
--- a/nestjs-BE/server/src/users/users.service.ts
+++ b/nestjs-BE/server/src/users/users.service.ts
@@ -1,7 +1,7 @@
 import { Injectable } from '@nestjs/common';
 import { PrismaService } from '../prisma/prisma.service';
 import { CreateUserPrismaDto } from './dto/create-user.dto';
-import { User } from '@prisma/client';
+import { Space, User } from '@prisma/client';
 import { v4 as uuid } from 'uuid';
 
 @Injectable()
@@ -35,4 +35,12 @@ export class UsersService {
       return user;
     });
   }
+
+  async findUserJoinedSpaces(userUuid: string): Promise<Space[]> {
+    const spaces = await this.prisma.space.findMany({
+      where: { profileSpaces: { some: { profile: { userUuid } } } },
+    });
+
+    return spaces;
+  }
 }

From 43f685df8419e709ea8ca611694b255547f80a8f Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Fri, 4 Oct 2024 16:52:20 +0900
Subject: [PATCH 02/28] =?UTF-8?q?test:=20UsersController=20=ED=85=8C?=
 =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../server/src/users/users.controller.spec.ts | 42 +++++++++++++++++++
 .../server/src/users/users.controller.ts      |  4 ++
 nestjs-BE/server/src/users/users.module.ts    |  2 +
 3 files changed, 48 insertions(+)
 create mode 100644 nestjs-BE/server/src/users/users.controller.spec.ts
 create mode 100644 nestjs-BE/server/src/users/users.controller.ts

diff --git a/nestjs-BE/server/src/users/users.controller.spec.ts b/nestjs-BE/server/src/users/users.controller.spec.ts
new file mode 100644
index 00000000..ea8344b5
--- /dev/null
+++ b/nestjs-BE/server/src/users/users.controller.spec.ts
@@ -0,0 +1,42 @@
+import { Test, TestingModule } from '@nestjs/testing';
+import { UsersController } from './users.controller';
+import { UsersService } from './users.service';
+import { HttpStatus } from '@nestjs/common';
+import { RequestWithUser } from '../utils/interface';
+
+describe('UsersController', () => {
+  let controller: UsersController;
+  let usersService: UsersService;
+
+  beforeEach(async () => {
+    const module: TestingModule = await Test.createTestingModule({
+      controllers: [UsersController],
+      providers: [
+        {
+          provide: UsersService,
+          useValue: { findUserJoinedSpaces: jest.fn() },
+        },
+      ],
+    }).compile();
+
+    controller = module.get<UsersController>(UsersController);
+    usersService = module.get<UsersService>(UsersService);
+  });
+
+  it('findUserJoinedSpaces', async () => {
+    const reqMock = { user: { uuid: 'user uuid' } } as RequestWithUser;
+    const spacesMock = [];
+
+    (usersService.findUserJoinedSpaces as jest.Mock).mockResolvedValue(
+      spacesMock,
+    );
+
+    const response = controller.findUserJoinedSpaces(reqMock);
+
+    await expect(response).resolves.toEqual({
+      statusCode: HttpStatus.OK,
+      message: 'OK',
+      data: spacesMock,
+    });
+  });
+});
diff --git a/nestjs-BE/server/src/users/users.controller.ts b/nestjs-BE/server/src/users/users.controller.ts
new file mode 100644
index 00000000..43b3842a
--- /dev/null
+++ b/nestjs-BE/server/src/users/users.controller.ts
@@ -0,0 +1,4 @@
+import { Controller } from '@nestjs/common';
+
+@Controller('users')
+export class UsersController {}
diff --git a/nestjs-BE/server/src/users/users.module.ts b/nestjs-BE/server/src/users/users.module.ts
index 8fa904f1..276e9b63 100644
--- a/nestjs-BE/server/src/users/users.module.ts
+++ b/nestjs-BE/server/src/users/users.module.ts
@@ -1,7 +1,9 @@
 import { Module } from '@nestjs/common';
 import { UsersService } from './users.service';
+import { UsersController } from './users.controller';
 
 @Module({
+  controllers: [UsersController],
   providers: [UsersService],
   exports: [UsersService],
 })

From e63ef8a649b62e0d044b23c641355477748e60ad Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Fri, 4 Oct 2024 17:06:46 +0900
Subject: [PATCH 03/28] =?UTF-8?q?fix:=20PrismaModule=20=EC=9D=98=EC=A1=B4?=
 =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 nestjs-BE/server/src/users/users.module.ts | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/nestjs-BE/server/src/users/users.module.ts b/nestjs-BE/server/src/users/users.module.ts
index 276e9b63..acfee4ee 100644
--- a/nestjs-BE/server/src/users/users.module.ts
+++ b/nestjs-BE/server/src/users/users.module.ts
@@ -1,8 +1,10 @@
 import { Module } from '@nestjs/common';
 import { UsersService } from './users.service';
 import { UsersController } from './users.controller';
+import { PrismaModule } from '../prisma/prisma.module';
 
 @Module({
+  imports: [PrismaModule],
   controllers: [UsersController],
   providers: [UsersService],
   exports: [UsersService],

From e6c970193de6e3c408d6ff41acdff0b57cce9764 Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Fri, 4 Oct 2024 18:25:12 +0900
Subject: [PATCH 04/28] =?UTF-8?q?test:=20e2e=20=ED=85=8C=EC=8A=A4=ED=8A=B8?=
 =?UTF-8?q?=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 nestjs-BE/server/test/users.e2e-spec.ts | 102 ++++++++++++++++++++++++
 1 file changed, 102 insertions(+)
 create mode 100644 nestjs-BE/server/test/users.e2e-spec.ts

diff --git a/nestjs-BE/server/test/users.e2e-spec.ts b/nestjs-BE/server/test/users.e2e-spec.ts
new file mode 100644
index 00000000..128d2e61
--- /dev/null
+++ b/nestjs-BE/server/test/users.e2e-spec.ts
@@ -0,0 +1,102 @@
+import { HttpStatus, INestApplication } from '@nestjs/common';
+import { Test, TestingModule } from '@nestjs/testing';
+import { ConfigModule, ConfigService } from '@nestjs/config';
+import { User } from '@prisma/client';
+import * as request from 'supertest';
+import { v4 as uuid } from 'uuid';
+import { sign } from 'jsonwebtoken';
+import { PrismaService } from '../src/prisma/prisma.service';
+import { UsersModule } from '../src/users/users.module';
+import { AuthModule } from '../src/auth/auth.module';
+
+describe('UsersController (e2e)', () => {
+  let app: INestApplication;
+  let prisma: PrismaService;
+  let configService: ConfigService;
+  let testToken: string;
+  let testUser: User;
+
+  beforeAll(async () => {
+    const module: TestingModule = await Test.createTestingModule({
+      imports: [
+        ConfigModule.forRoot({ isGlobal: true }),
+        UsersModule,
+        AuthModule,
+      ],
+    }).compile();
+
+    app = module.createNestApplication();
+
+    await app.init();
+
+    prisma = module.get<PrismaService>(PrismaService);
+    configService = module.get<ConfigService>(ConfigService);
+
+    await prisma.user.deleteMany({});
+
+    testUser = await prisma.user.create({ data: { uuid: uuid() } });
+    testToken = sign(
+      { sub: testUser.uuid },
+      configService.get<string>('JWT_ACCESS_SECRET'),
+      { expiresIn: '5m' },
+    );
+  });
+
+  beforeEach(async () => {
+    await prisma.profile.deleteMany({});
+    await prisma.space.deleteMany({});
+    await prisma.profileSpace.deleteMany({});
+  });
+
+  afterAll(async () => {
+    await app.close();
+  });
+
+  it('users/spaces (GET)', async () => {
+    const SPACE_NUMBER = 5;
+
+    const profile = await prisma.profile.create({
+      data: {
+        uuid: uuid(),
+        userUuid: testUser.uuid,
+        image: 'test image',
+        nickname: 'test nickname',
+      },
+    });
+    const spaces = [];
+    for (let j = 0; j < SPACE_NUMBER; j++) {
+      const space = await prisma.space.create({
+        data: { uuid: uuid(), name: 'test space', icon: 'test icon' },
+      });
+      await prisma.profileSpace.create({
+        data: { profileUuid: profile.uuid, spaceUuid: space.uuid },
+      });
+      spaces.push(space);
+    }
+
+    return request(app.getHttpServer())
+      .get('/users/spaces')
+      .auth(testToken, { type: 'bearer' })
+      .expect(HttpStatus.OK)
+      .expect((res) => {
+        expect(res.body.statusCode).toBe(HttpStatus.OK);
+        expect(res.body.message).toBe('OK');
+        expect(res.body.data).toEqual(expect.arrayContaining(spaces));
+      });
+  });
+
+  it('users/spaces (GET) no joined spaces', async () => {
+    return request(app.getHttpServer())
+      .get('/users/spaces')
+      .auth(testToken, { type: 'bearer' })
+      .expect(HttpStatus.OK)
+      .expect({ statusCode: HttpStatus.OK, message: 'OK', data: [] });
+  });
+
+  it('users/spaces (GET)', async () => {
+    return request(app.getHttpServer())
+      .get('/users/spaces')
+      .expect(HttpStatus.UNAUTHORIZED)
+      .expect({ statusCode: HttpStatus.UNAUTHORIZED, message: 'Unauthorized' });
+  });
+});

From 8649827e44b6d1a75cdcede671099dff5e625da8 Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Fri, 4 Oct 2024 18:29:00 +0900
Subject: [PATCH 05/28] =?UTF-8?q?feat:=20=EC=9C=A0=EC=A0=80=EA=B0=80=20?=
 =?UTF-8?q?=EB=93=A4=EC=96=B4=EA=B0=84=20=EC=8A=A4=ED=8E=98=EC=9D=B4?=
 =?UTF-8?q?=EC=8A=A4=20=EB=AA=A9=EB=A1=9D=20API?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../server/src/users/users.controller.ts      | 26 +++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/nestjs-BE/server/src/users/users.controller.ts b/nestjs-BE/server/src/users/users.controller.ts
index 43b3842a..a2256192 100644
--- a/nestjs-BE/server/src/users/users.controller.ts
+++ b/nestjs-BE/server/src/users/users.controller.ts
@@ -1,4 +1,26 @@
-import { Controller } from '@nestjs/common';
+import { Controller, Get, HttpStatus, Req } from '@nestjs/common';
+import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
+import { UsersService } from './users.service';
+import { RequestWithUser } from '../utils/interface';
 
 @Controller('users')
-export class UsersController {}
+@ApiTags('users')
+export class UsersController {
+  constructor(private readonly usersService: UsersService) {}
+
+  @Get('spaces')
+  @ApiOperation({ summary: 'Get spaces user joined.' })
+  @ApiResponse({
+    status: HttpStatus.OK,
+    description: 'Spaces found.',
+  })
+  @ApiResponse({
+    status: HttpStatus.UNAUTHORIZED,
+    description: 'User not logged in.',
+  })
+  async findUserJoinedSpaces(@Req() req: RequestWithUser) {
+    const spaces = await this.usersService.findUserJoinedSpaces(req.user.uuid);
+
+    return { statusCode: HttpStatus.OK, message: 'OK', data: spaces };
+  }
+}

From 29beac15ffacd1b703b0274e56da0830a2f5187a Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Fri, 4 Oct 2024 18:37:23 +0900
Subject: [PATCH 06/28] =?UTF-8?q?refactor:=20=EB=B9=84=EB=8F=99=EA=B8=B0?=
 =?UTF-8?q?=20=EB=8F=99=EC=9E=91=20=EA=B0=9C=EC=84=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 nestjs-BE/server/test/users.e2e-spec.ts | 27 ++++++++++++++++---------
 1 file changed, 17 insertions(+), 10 deletions(-)

diff --git a/nestjs-BE/server/test/users.e2e-spec.ts b/nestjs-BE/server/test/users.e2e-spec.ts
index 128d2e61..1f55a7a5 100644
--- a/nestjs-BE/server/test/users.e2e-spec.ts
+++ b/nestjs-BE/server/test/users.e2e-spec.ts
@@ -63,16 +63,23 @@ describe('UsersController (e2e)', () => {
         nickname: 'test nickname',
       },
     });
-    const spaces = [];
-    for (let j = 0; j < SPACE_NUMBER; j++) {
-      const space = await prisma.space.create({
-        data: { uuid: uuid(), name: 'test space', icon: 'test icon' },
-      });
-      await prisma.profileSpace.create({
-        data: { profileUuid: profile.uuid, spaceUuid: space.uuid },
-      });
-      spaces.push(space);
-    }
+    const spacePromises = Array.from({ length: SPACE_NUMBER }, async () => {
+      return prisma.space
+        .create({
+          data: { uuid: uuid(), name: 'test space', icon: 'test icon' },
+        })
+        .then(async (space) => {
+          return prisma.profileSpace
+            .create({
+              data: {
+                profileUuid: profile.uuid,
+                spaceUuid: space.uuid,
+              },
+            })
+            .then(() => space);
+        });
+    });
+    const spaces = await Promise.all(spacePromises);
 
     return request(app.getHttpServer())
       .get('/users/spaces')

From aeb19dbe4916894e3cb8559e6604a4fa8998f697 Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Sat, 5 Oct 2024 16:54:44 +0900
Subject: [PATCH 07/28] =?UTF-8?q?feat:=20=EC=9D=B4=EC=A0=84=20=EB=B2=84?=
 =?UTF-8?q?=EC=A0=84=20=EC=A0=9C=EA=B1=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../server/src/spaces/dto/create-space.dto.ts |  16 +--
 .../server/src/spaces/dto/update-space.dto.ts |  21 +---
 .../src/spaces/spaces.controller.spec.ts      |  34 +++---
 .../server/src/spaces/spaces.controller.ts    | 105 +-----------------
 nestjs-BE/server/src/spaces/spaces.module.ts  |   4 +-
 nestjs-BE/server/test/spaces.e2e-spec.ts      |  88 +++++++--------
 6 files changed, 71 insertions(+), 197 deletions(-)

diff --git a/nestjs-BE/server/src/spaces/dto/create-space.dto.ts b/nestjs-BE/server/src/spaces/dto/create-space.dto.ts
index 4e3414a0..11ba7b08 100644
--- a/nestjs-BE/server/src/spaces/dto/create-space.dto.ts
+++ b/nestjs-BE/server/src/spaces/dto/create-space.dto.ts
@@ -4,7 +4,7 @@ import { MAX_NAME_LENGTH } from '../../config/magic-number';
 import { Expose } from 'class-transformer';
 import { v4 as uuid } from 'uuid';
 
-export class CreateSpaceRequestV2Dto {
+export class CreateSpaceRequestDto {
   @IsString()
   @IsNotEmpty()
   @MaxLength(MAX_NAME_LENGTH)
@@ -24,20 +24,6 @@ export class CreateSpaceRequestV2Dto {
   icon: string;
 }
 
-export class CreateSpaceRequestDto {
-  @IsString()
-  @IsNotEmpty()
-  @MaxLength(MAX_NAME_LENGTH)
-  @ApiProperty({ example: 'Sample Space', description: 'Name of the space' })
-  name: string;
-
-  @ApiProperty({
-    example: 'space-icon.png',
-    description: 'Profile icon for the space',
-  })
-  icon: string;
-}
-
 export class CreateSpacePrismaDto {
   name: string;
   icon: string;
diff --git a/nestjs-BE/server/src/spaces/dto/update-space.dto.ts b/nestjs-BE/server/src/spaces/dto/update-space.dto.ts
index 2af0b07e..56d141c5 100644
--- a/nestjs-BE/server/src/spaces/dto/update-space.dto.ts
+++ b/nestjs-BE/server/src/spaces/dto/update-space.dto.ts
@@ -2,7 +2,7 @@ import { ApiProperty } from '@nestjs/swagger';
 import { IsNotEmpty, IsOptional, IsString, MaxLength } from 'class-validator';
 import { MAX_NAME_LENGTH } from '../../config/magic-number';
 
-export class UpdateSpaceRequestV2Dto {
+export class UpdateSpaceRequestDto {
   @IsOptional()
   @IsString()
   @IsNotEmpty()
@@ -23,25 +23,6 @@ export class UpdateSpaceRequestV2Dto {
   icon: string;
 }
 
-export class UpdateSpaceRequestDto {
-  @IsString()
-  @IsNotEmpty()
-  @MaxLength(MAX_NAME_LENGTH)
-  @ApiProperty({
-    example: 'new space',
-    description: 'Updated space name',
-    required: false,
-  })
-  name: string;
-
-  @ApiProperty({
-    example: 'new image',
-    description: 'Updated space icon',
-    required: false,
-  })
-  icon: string;
-}
-
 export class UpdateSpacePrismaDto {
   name: string;
   icon: string;
diff --git a/nestjs-BE/server/src/spaces/spaces.controller.spec.ts b/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
index fdc36092..bff5fa59 100644
--- a/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
+++ b/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
@@ -1,5 +1,5 @@
 import { Test, TestingModule } from '@nestjs/testing';
-import { SpacesControllerV2 } from './spaces.controller';
+import { SpacesController } from './spaces.controller';
 import { SpacesService } from './spaces.service';
 import { ProfileSpaceService } from '../profile-space/profile-space.service';
 import { UploadService } from '../upload/upload.service';
@@ -11,13 +11,13 @@ import {
   HttpStatus,
   NotFoundException,
 } from '@nestjs/common';
-import { UpdateSpaceRequestV2Dto } from './dto/update-space.dto';
-import { CreateSpaceRequestV2Dto } from './dto/create-space.dto';
+import { UpdateSpaceRequestDto } from './dto/update-space.dto';
+import { CreateSpaceRequestDto } from './dto/create-space.dto';
 import { RequestWithUser } from '../utils/interface';
 import { ConfigModule, ConfigService } from '@nestjs/config';
 
-describe('SpacesControllerV2', () => {
-  let controller: SpacesControllerV2;
+describe('SpacesController', () => {
+  let controller: SpacesController;
   let spacesService: SpacesService;
   let uploadService: UploadService;
   let profilesService: ProfilesService;
@@ -27,7 +27,7 @@ describe('SpacesControllerV2', () => {
   beforeEach(async () => {
     const module: TestingModule = await Test.createTestingModule({
       imports: [ConfigModule],
-      controllers: [SpacesControllerV2],
+      controllers: [SpacesController],
       providers: [
         {
           provide: SpacesService,
@@ -55,7 +55,7 @@ describe('SpacesControllerV2', () => {
       ],
     }).compile();
 
-    controller = module.get<SpacesControllerV2>(SpacesControllerV2);
+    controller = module.get<SpacesController>(SpacesController);
     spacesService = module.get<SpacesService>(SpacesService);
     uploadService = module.get<UploadService>(UploadService);
     profilesService = module.get<ProfilesService>(ProfilesService);
@@ -74,7 +74,7 @@ describe('SpacesControllerV2', () => {
     const bodyMock = {
       name: 'new space name',
       profileUuid: profileMock.uuid,
-    } as CreateSpaceRequestV2Dto;
+    } as CreateSpaceRequestDto;
     const spaceMock = { uuid: 'space uuid' } as Space;
 
     jest
@@ -103,7 +103,7 @@ describe('SpacesControllerV2', () => {
     const bodyMock = {
       name: 'new space name',
       profileUuid: 'wrong profile uuid',
-    } as CreateSpaceRequestV2Dto;
+    } as CreateSpaceRequestDto;
     const requestMock = { user: { uuid: 'user uuid' } } as RequestWithUser;
 
     jest
@@ -127,7 +127,7 @@ describe('SpacesControllerV2', () => {
     const bodyMock = {
       name: 'new space name',
       profileUuid: profileMock.uuid,
-    } as CreateSpaceRequestV2Dto;
+    } as CreateSpaceRequestDto;
 
     jest
       .spyOn(profilesService, 'findProfileByProfileUuid')
@@ -149,7 +149,7 @@ describe('SpacesControllerV2', () => {
     const bodyMock = {
       name: 'new space name',
       profileUuid: profileMock.uuid,
-    } as CreateSpaceRequestV2Dto;
+    } as CreateSpaceRequestDto;
     const spaceMock = { uuid: 'space uuid' } as Space;
 
     jest
@@ -318,7 +318,7 @@ describe('SpacesControllerV2', () => {
       uuid: 'profile uuid',
       userUuid: requestMock.user.uuid,
     } as Profile;
-    const bodyMock = { name: 'new space name' } as UpdateSpaceRequestV2Dto;
+    const bodyMock = { name: 'new space name' } as UpdateSpaceRequestDto;
     const profileSpaceMock = {
       spaceUuid: spaceMock.uuid,
       profileUuid: profileMock.uuid,
@@ -354,7 +354,7 @@ describe('SpacesControllerV2', () => {
   });
 
   it('update icon not requested', async () => {
-    const bodyMock = { name: 'new space name' } as UpdateSpaceRequestV2Dto;
+    const bodyMock = { name: 'new space name' } as UpdateSpaceRequestDto;
     const spaceMock = { uuid: 'space uuid' } as Space;
     const requestMock = { user: { uuid: 'user uuid' } } as RequestWithUser;
     const profileMock = {
@@ -396,7 +396,7 @@ describe('SpacesControllerV2', () => {
   it('update name not requested', async () => {
     const iconMock = { filename: 'icon' } as Express.Multer.File;
     const iconUrlMock = 'www.test.com/image';
-    const bodyMock = {} as UpdateSpaceRequestV2Dto;
+    const bodyMock = {} as UpdateSpaceRequestDto;
     const spaceMock = { uuid: 'space uuid' } as Space;
     const requestMock = { user: { uuid: 'user uuid' } } as RequestWithUser;
     const profileMock = {
@@ -444,7 +444,7 @@ describe('SpacesControllerV2', () => {
       uuid: 'profile uuid',
       userUuid: 'new user uuid',
     } as Profile;
-    const bodyMock = { name: 'new space name' } as UpdateSpaceRequestV2Dto;
+    const bodyMock = { name: 'new space name' } as UpdateSpaceRequestDto;
 
     jest
       .spyOn(profilesService, 'findProfileByProfileUuid')
@@ -471,7 +471,7 @@ describe('SpacesControllerV2', () => {
       uuid: 'profile uuid',
       userUuid: requestMock.user.uuid,
     } as Profile;
-    const bodyMock = { name: 'new space name' } as UpdateSpaceRequestV2Dto;
+    const bodyMock = { name: 'new space name' } as UpdateSpaceRequestDto;
 
     jest
       .spyOn(profilesService, 'findProfileByProfileUuid')
@@ -501,7 +501,7 @@ describe('SpacesControllerV2', () => {
       uuid: 'profile uuid',
       userUuid: requestMock.user.uuid,
     } as Profile;
-    const bodyMock = { name: 'new space name' } as UpdateSpaceRequestV2Dto;
+    const bodyMock = { name: 'new space name' } as UpdateSpaceRequestDto;
 
     jest
       .spyOn(profilesService, 'findProfileByProfileUuid')
diff --git a/nestjs-BE/server/src/spaces/spaces.controller.ts b/nestjs-BE/server/src/spaces/spaces.controller.ts
index fbf7df6c..9ac17081 100644
--- a/nestjs-BE/server/src/spaces/spaces.controller.ts
+++ b/nestjs-BE/server/src/spaces/spaces.controller.ts
@@ -18,14 +18,8 @@ import {
 } from '@nestjs/common';
 import { FileInterceptor } from '@nestjs/platform-express';
 import { SpacesService } from './spaces.service';
-import {
-  CreateSpaceRequestDto,
-  CreateSpaceRequestV2Dto,
-} from './dto/create-space.dto';
-import {
-  UpdateSpaceRequestDto,
-  UpdateSpaceRequestV2Dto,
-} from './dto/update-space.dto';
+import { CreateSpaceRequestDto } from './dto/create-space.dto';
+import { UpdateSpaceRequestDto } from './dto/update-space.dto';
 import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger';
 import { UploadService } from '../upload/upload.service';
 import { ProfileSpaceService } from '../profile-space/profile-space.service';
@@ -33,9 +27,9 @@ import { RequestWithUser } from '../utils/interface';
 import { ProfilesService } from '../profiles/profiles.service';
 import { ConfigService } from '@nestjs/config';
 
-@Controller('v2/spaces')
+@Controller('spaces')
 @ApiTags('spaces')
-export class SpacesControllerV2 {
+export class SpacesController {
   constructor(
     private readonly spacesService: SpacesService,
     private readonly uploadService: UploadService,
@@ -76,7 +70,7 @@ export class SpacesControllerV2 {
         disableErrorMessages: true,
       }),
     )
-    createSpaceDto: CreateSpaceRequestV2Dto,
+    createSpaceDto: CreateSpaceRequestDto,
     @Req() req: RequestWithUser,
   ) {
     if (!createSpaceDto.profileUuid) throw new BadRequestException();
@@ -170,7 +164,7 @@ export class SpacesControllerV2 {
     @Param('space_uuid') spaceUuid: string,
     @Query('profile_uuid') profileUuid: string,
     @Body(new ValidationPipe({ whitelist: true, disableErrorMessages: true }))
-    updateSpaceDto: UpdateSpaceRequestV2Dto,
+    updateSpaceDto: UpdateSpaceRequestDto,
     @Req() req: RequestWithUser,
   ) {
     if (!profileUuid) throw new BadRequestException();
@@ -197,90 +191,3 @@ export class SpacesControllerV2 {
     return { statusCode: HttpStatus.OK, message: 'OK', data: space };
   }
 }
-
-/*
-  OLD VERSION
-*/
-@Controller('spaces')
-@ApiTags('spaces')
-export class SpacesController {
-  constructor(
-    private readonly spacesService: SpacesService,
-    private readonly uploadService: UploadService,
-    private readonly profileSpaceService: ProfileSpaceService,
-    private readonly profilesService: ProfilesService,
-    private readonly configService: ConfigService,
-  ) {}
-
-  @Post()
-  @UseInterceptors(FileInterceptor('icon'))
-  @ApiOperation({ summary: 'Create space' })
-  @ApiResponse({
-    status: 201,
-    description: 'The space has been successfully created.',
-  })
-  async create(
-    @UploadedFile() icon: Express.Multer.File,
-    @Body(new ValidationPipe({ whitelist: true, disableErrorMessages: true }))
-    createSpaceDto: CreateSpaceRequestDto,
-    @Req() req: RequestWithUser,
-  ) {
-    const profile = await this.profilesService.findProfile(req.user.uuid);
-    if (!profile) throw new NotFoundException();
-    const iconUrl = icon
-      ? await this.uploadService.uploadFile(icon)
-      : this.configService.get<string>('APP_ICON_URL');
-    createSpaceDto.icon = iconUrl;
-    const space = await this.spacesService.createSpace(createSpaceDto);
-    await this.profileSpaceService.joinSpace(profile.uuid, space.uuid);
-    return { statusCode: 201, message: 'Created', data: space };
-  }
-
-  @Get(':space_uuid')
-  @ApiOperation({ summary: 'Get space by space_uuid' })
-  @ApiResponse({
-    status: 200,
-    description: 'Return the space data.',
-  })
-  @ApiResponse({
-    status: 404,
-    description: 'Space not found.',
-  })
-  async findOne(@Param('space_uuid') spaceUuid: string) {
-    const space = await this.spacesService.findSpace(spaceUuid);
-    if (!space) throw new NotFoundException();
-    return { statusCode: 200, message: 'Success', data: space };
-  }
-
-  @Patch(':space_uuid')
-  @UseInterceptors(FileInterceptor('icon'))
-  @ApiOperation({ summary: 'Update space by space_uuid' })
-  @ApiResponse({
-    status: 200,
-    description: 'Space has been successfully updated.',
-  })
-  @ApiResponse({
-    status: 400,
-    description: 'Bad Request. Invalid input data.',
-  })
-  @ApiResponse({
-    status: 404,
-    description: 'Space not found.',
-  })
-  async update(
-    @UploadedFile() icon: Express.Multer.File,
-    @Param('space_uuid') spaceUuid: string,
-    @Body(new ValidationPipe({ whitelist: true, disableErrorMessages: true }))
-    updateSpaceDto: UpdateSpaceRequestDto,
-  ) {
-    if (icon) {
-      updateSpaceDto.icon = await this.uploadService.uploadFile(icon);
-    }
-    const space = await this.spacesService.updateSpace(
-      spaceUuid,
-      updateSpaceDto,
-    );
-    if (!space) throw new NotFoundException();
-    return { statusCode: 200, message: 'Success', data: space };
-  }
-}
diff --git a/nestjs-BE/server/src/spaces/spaces.module.ts b/nestjs-BE/server/src/spaces/spaces.module.ts
index f3a866a7..52c1bf25 100644
--- a/nestjs-BE/server/src/spaces/spaces.module.ts
+++ b/nestjs-BE/server/src/spaces/spaces.module.ts
@@ -1,13 +1,13 @@
 import { forwardRef, Module } from '@nestjs/common';
 import { SpacesService } from './spaces.service';
-import { SpacesController, SpacesControllerV2 } from './spaces.controller';
+import { SpacesController } from './spaces.controller';
 import { UploadModule } from '../upload/upload.module';
 import { ProfileSpaceModule } from '../profile-space/profile-space.module';
 import { ProfilesModule } from '../profiles/profiles.module';
 
 @Module({
   imports: [forwardRef(() => ProfileSpaceModule), ProfilesModule, UploadModule],
-  controllers: [SpacesController, SpacesControllerV2],
+  controllers: [SpacesController],
   providers: [SpacesService],
   exports: [SpacesService],
 })
diff --git a/nestjs-BE/server/test/spaces.e2e-spec.ts b/nestjs-BE/server/test/spaces.e2e-spec.ts
index 9792462f..322b28b6 100644
--- a/nestjs-BE/server/test/spaces.e2e-spec.ts
+++ b/nestjs-BE/server/test/spaces.e2e-spec.ts
@@ -75,7 +75,7 @@ describe('SpacesController (e2e)', () => {
     await app.close();
   });
 
-  it('/v2/spaces (POST)', () => {
+  it('/spaces (POST)', () => {
     const newSpace = {
       name: 'new test space',
       icon: testImagePath,
@@ -90,7 +90,7 @@ describe('SpacesController (e2e)', () => {
     const imageRegExp = new RegExp(imageUrlPattern);
 
     return request(app.getHttpServer())
-      .post('/v2/spaces')
+      .post('/spaces')
       .auth(testToken, { type: 'bearer' })
       .field('name', newSpace.name)
       .field('profile_uuid', testProfile.uuid)
@@ -107,11 +107,11 @@ describe('SpacesController (e2e)', () => {
       });
   });
 
-  it('/v2/spaces (POST) without space image', () => {
+  it('/spaces (POST) without space image', () => {
     const newSpace = { name: 'new test space' };
 
     return request(app.getHttpServer())
-      .post('/v2/spaces')
+      .post('/spaces')
       .auth(testToken, { type: 'bearer' })
       .send({ name: newSpace.name, profile_uuid: testProfile.uuid })
       .expect(HttpStatus.CREATED)
@@ -128,7 +128,7 @@ describe('SpacesController (e2e)', () => {
       });
   });
 
-  it('/v2/spaces (POST) without profile uuid', () => {
+  it('/spaces (POST) without profile uuid', () => {
     const newSpace = {
       name: 'new test space',
       icon: testImagePath,
@@ -136,7 +136,7 @@ describe('SpacesController (e2e)', () => {
     };
 
     return request(app.getHttpServer())
-      .post('/v2/spaces')
+      .post('/spaces')
       .auth(testToken, { type: 'bearer' })
       .field('name', newSpace.name)
       .attach('icon', newSpace.icon, { contentType: newSpace.iconContentType })
@@ -144,14 +144,14 @@ describe('SpacesController (e2e)', () => {
       .expect({ message: 'Bad Request', statusCode: HttpStatus.BAD_REQUEST });
   });
 
-  it('/v2/spaces (POST) without space name', () => {
+  it('/spaces (POST) without space name', () => {
     const newSpace = {
       icon: testImagePath,
       iconContentType: 'image/png',
     };
 
     return request(app.getHttpServer())
-      .post('/v2/spaces')
+      .post('/spaces')
       .auth(testToken, { type: 'bearer' })
       .field('profile_uuid', testProfile.uuid)
       .attach('icon', newSpace.icon, { contentType: newSpace.iconContentType })
@@ -159,14 +159,14 @@ describe('SpacesController (e2e)', () => {
       .expect({ message: 'Bad Request', statusCode: HttpStatus.BAD_REQUEST });
   });
 
-  it('/v2/spaces (POST) not logged in', () => {
+  it('/spaces (POST) not logged in', () => {
     return request(app.getHttpServer())
-      .post('/v2/spaces')
+      .post('/spaces')
       .expect(HttpStatus.UNAUTHORIZED)
       .expect({ message: 'Unauthorized', statusCode: HttpStatus.UNAUTHORIZED });
   });
 
-  it("/v2/spaces (POST) profile user doesn't have", async () => {
+  it("/spaces (POST) profile user doesn't have", async () => {
     const newSpace = {
       name: 'new test space',
       icon: testImagePath,
@@ -183,7 +183,7 @@ describe('SpacesController (e2e)', () => {
     });
 
     return request(app.getHttpServer())
-      .post('/v2/spaces')
+      .post('/spaces')
       .auth(testToken, { type: 'bearer' })
       .field('name', newSpace.name)
       .field('profile_uuid', newProfile.uuid)
@@ -192,7 +192,7 @@ describe('SpacesController (e2e)', () => {
       .expect({ message: 'Forbidden', statusCode: HttpStatus.FORBIDDEN });
   });
 
-  it('/v2/spaces (POST) profilie not found', () => {
+  it('/spaces (POST) profilie not found', () => {
     const newSpace = {
       name: 'new test space',
       icon: testImagePath,
@@ -200,7 +200,7 @@ describe('SpacesController (e2e)', () => {
     };
 
     return request(app.getHttpServer())
-      .post('/v2/spaces')
+      .post('/spaces')
       .auth(testToken, { type: 'bearer' })
       .field('name', newSpace.name)
       .field('profile_uuid', uuid())
@@ -209,13 +209,13 @@ describe('SpacesController (e2e)', () => {
       .expect({ message: 'Not Found', statusCode: HttpStatus.NOT_FOUND });
   });
 
-  it('/v2/spaces/:space_uuid?profile_uuid={profile_uuid} (GET) space found', async () => {
+  it('/spaces/:space_uuid?profile_uuid={profile_uuid} (GET) space found', async () => {
     await prisma.profileSpace.create({
       data: { spaceUuid: testSpace.uuid, profileUuid: testProfile.uuid },
     });
 
     return request(app.getHttpServer())
-      .get(`/v2/spaces/${testSpace.uuid}?profile_uuid=${testProfile.uuid}`)
+      .get(`/spaces/${testSpace.uuid}?profile_uuid=${testProfile.uuid}`)
       .auth(testToken, { type: 'bearer' })
       .expect(HttpStatus.OK)
       .expect({
@@ -225,26 +225,26 @@ describe('SpacesController (e2e)', () => {
       });
   });
 
-  it('/v2/spaces/:space_uuid?profile_uuid={profile_uuid} (GET) query profile_uuid needed', async () => {
+  it('/spaces/:space_uuid?profile_uuid={profile_uuid} (GET) query profile_uuid needed', async () => {
     return request(app.getHttpServer())
-      .get(`/v2/spaces/${testSpace.uuid}`)
+      .get(`/spaces/${testSpace.uuid}`)
       .auth(testToken, { type: 'bearer' })
       .expect(HttpStatus.BAD_REQUEST)
       .expect({ message: 'Bad Request', statusCode: HttpStatus.BAD_REQUEST });
   });
 
-  it('/v2/spaces/:space_uuid?profile_uuid={profile_uuid} (GET) not logged in', async () => {
+  it('/spaces/:space_uuid?profile_uuid={profile_uuid} (GET) not logged in', async () => {
     await prisma.profileSpace.create({
       data: { spaceUuid: testSpace.uuid, profileUuid: testProfile.uuid },
     });
 
     return request(app.getHttpServer())
-      .get(`/v2/spaces/${testSpace.uuid}?profile_uuid=${testProfile.uuid}`)
+      .get(`/spaces/${testSpace.uuid}?profile_uuid=${testProfile.uuid}`)
       .expect(HttpStatus.UNAUTHORIZED)
       .expect({ message: 'Unauthorized', statusCode: HttpStatus.UNAUTHORIZED });
   });
 
-  it("/v2/spaces/:space_uuid?profile_uuid={profile_uuid} (GET) profile user doesn't have", async () => {
+  it("/spaces/:space_uuid?profile_uuid={profile_uuid} (GET) profile user doesn't have", async () => {
     const newUser = await prisma.user.create({ data: { uuid: uuid() } });
     const newProfile = await prisma.profile.create({
       data: {
@@ -259,37 +259,37 @@ describe('SpacesController (e2e)', () => {
     });
 
     return request(app.getHttpServer())
-      .get(`/v2/spaces/${testSpace.uuid}?profile_uuid=${newProfile.uuid}`)
+      .get(`/spaces/${testSpace.uuid}?profile_uuid=${newProfile.uuid}`)
       .auth(testToken, { type: 'bearer' })
       .expect(HttpStatus.FORBIDDEN)
       .expect({ message: 'Forbidden', statusCode: HttpStatus.FORBIDDEN });
   });
 
-  it('/v2/spaces/:space_uuid?profile_uuid={profile_uuid} (GET) profile not existing', async () => {
+  it('/spaces/:space_uuid?profile_uuid={profile_uuid} (GET) profile not existing', async () => {
     return request(app.getHttpServer())
-      .get(`/v2/spaces/${testSpace.uuid}?profile_uuid=${uuid()}`)
+      .get(`/spaces/${testSpace.uuid}?profile_uuid=${uuid()}`)
       .auth(testToken, { type: 'bearer' })
       .expect(HttpStatus.NOT_FOUND)
       .expect({ message: 'Not Found', statusCode: HttpStatus.NOT_FOUND });
   });
 
-  it('/v2/spaces/:space_uuid?profile_uuid={profile_uuid} (GET) findOne profile not joined space', () => {
+  it('/spaces/:space_uuid?profile_uuid={profile_uuid} (GET) findOne profile not joined space', () => {
     return request(app.getHttpServer())
-      .get(`/v2/spaces/${testSpace.uuid}?profile_uuid=${testProfile.uuid}`)
+      .get(`/spaces/${testSpace.uuid}?profile_uuid=${testProfile.uuid}`)
       .auth(testToken, { type: 'bearer' })
       .expect(HttpStatus.FORBIDDEN)
       .expect({ message: 'Forbidden', statusCode: HttpStatus.FORBIDDEN });
   });
 
-  it('/v2/spaces/:space_uuid?profile_uuid={profile_uuid} (GET) not existing space', () => {
+  it('/spaces/:space_uuid?profile_uuid={profile_uuid} (GET) not existing space', () => {
     return request(app.getHttpServer())
-      .get(`/v2/spaces/${uuid()}?profile_uuid=${testProfile.uuid}`)
+      .get(`/spaces/${uuid()}?profile_uuid=${testProfile.uuid}`)
       .auth(testToken, { type: 'bearer' })
       .expect(HttpStatus.NOT_FOUND)
       .expect({ message: 'Not Found', statusCode: HttpStatus.NOT_FOUND });
   });
 
-  it('/v2/spaces/:space_uuid?profile_uuid={profile_uuid} (PATCH) update success', async () => {
+  it('/spaces/:space_uuid?profile_uuid={profile_uuid} (PATCH) update success', async () => {
     const newSpace = {
       name: 'new test space',
       icon: testImagePath,
@@ -306,7 +306,7 @@ describe('SpacesController (e2e)', () => {
     const imageRegExp = new RegExp(imageUrlPattern);
 
     return request(app.getHttpServer())
-      .patch(`/v2/spaces/${testSpace.uuid}?profile_uuid=${testProfile.uuid}`)
+      .patch(`/spaces/${testSpace.uuid}?profile_uuid=${testProfile.uuid}`)
       .auth(testToken, { type: 'bearer' })
       .field('name', newSpace.name)
       .attach('icon', newSpace.icon, { contentType: newSpace.iconContentType })
@@ -320,7 +320,7 @@ describe('SpacesController (e2e)', () => {
       });
   });
 
-  it('/v2/spaces/:space_uuid?profile_uuid={profile_uuid} (PATCH) request without name', async () => {
+  it('/spaces/:space_uuid?profile_uuid={profile_uuid} (PATCH) request without name', async () => {
     const newSpace = {
       icon: testImagePath,
       iconContentType: 'image/png',
@@ -336,7 +336,7 @@ describe('SpacesController (e2e)', () => {
     });
 
     return request(app.getHttpServer())
-      .patch(`/v2/spaces/${testSpace.uuid}?profile_uuid=${testProfile.uuid}`)
+      .patch(`/spaces/${testSpace.uuid}?profile_uuid=${testProfile.uuid}`)
       .auth(testToken, { type: 'bearer' })
       .attach('icon', newSpace.icon, { contentType: newSpace.iconContentType })
       .expect(HttpStatus.OK)
@@ -349,14 +349,14 @@ describe('SpacesController (e2e)', () => {
       });
   });
 
-  it('/v2/spaces/:space_uuid?profile_uuid={profile_uuid} (PATCH) request without icon', async () => {
+  it('/spaces/:space_uuid?profile_uuid={profile_uuid} (PATCH) request without icon', async () => {
     const newSpace = { name: 'new test space' };
     await prisma.profileSpace.create({
       data: { spaceUuid: testSpace.uuid, profileUuid: testProfile.uuid },
     });
 
     return request(app.getHttpServer())
-      .patch(`/v2/spaces/${testSpace.uuid}?profile_uuid=${testProfile.uuid}`)
+      .patch(`/spaces/${testSpace.uuid}?profile_uuid=${testProfile.uuid}`)
       .auth(testToken, { type: 'bearer' })
       .send({ name: newSpace.name })
       .expect(HttpStatus.OK)
@@ -371,7 +371,7 @@ describe('SpacesController (e2e)', () => {
       });
   });
 
-  it('/v2/spaces/:space_uuid?profile_uuid={profile_uuid} (PATCH) profile uuid needed', async () => {
+  it('/spaces/:space_uuid?profile_uuid={profile_uuid} (PATCH) profile uuid needed', async () => {
     const newSpace = {
       name: 'new test space',
       icon: testImagePath,
@@ -379,7 +379,7 @@ describe('SpacesController (e2e)', () => {
     };
 
     return request(app.getHttpServer())
-      .patch(`/v2/spaces/${testSpace.uuid}`)
+      .patch(`/spaces/${testSpace.uuid}`)
       .auth(testToken, { type: 'bearer' })
       .field('name', newSpace.name)
       .attach('icon', newSpace.icon, { contentType: newSpace.iconContentType })
@@ -387,12 +387,12 @@ describe('SpacesController (e2e)', () => {
       .expect({ message: 'Bad Request', statusCode: HttpStatus.BAD_REQUEST });
   });
 
-  it('/v2/spaces/:space_uuid?profile_uuid={profile_uuid} (PATCH) unauthorized', async () => {
+  it('/spaces/:space_uuid?profile_uuid={profile_uuid} (PATCH) unauthorized', async () => {
     const icon = await readFile(resolve(__dirname, './base_image.png'));
     const newSpace = { name: 'new test space', icon };
 
     return request(app.getHttpServer())
-      .patch(`/v2/spaces/${testSpace.uuid}?profile_uuid=${testProfile.uuid}`)
+      .patch(`/spaces/${testSpace.uuid}?profile_uuid=${testProfile.uuid}`)
       .field('name', newSpace.name)
       .attach('icon', newSpace.icon)
       .expect(HttpStatus.UNAUTHORIZED)
@@ -402,7 +402,7 @@ describe('SpacesController (e2e)', () => {
       });
   });
 
-  it("/v2/spaces/:space_uuid?profile_uuid={profile_uuid} (PATCH) profile user doesn't have", async () => {
+  it("/spaces/:space_uuid?profile_uuid={profile_uuid} (PATCH) profile user doesn't have", async () => {
     const newSpace = {
       name: 'new test space',
       icon: testImagePath,
@@ -422,7 +422,7 @@ describe('SpacesController (e2e)', () => {
     });
 
     return request(app.getHttpServer())
-      .patch(`/v2/spaces/${testSpace.uuid}?profile_uuid=${newProfile.uuid}`)
+      .patch(`/spaces/${testSpace.uuid}?profile_uuid=${newProfile.uuid}`)
       .auth(testToken, { type: 'bearer' })
       .field('name', newSpace.name)
       .attach('icon', newSpace.icon, { contentType: newSpace.iconContentType })
@@ -430,7 +430,7 @@ describe('SpacesController (e2e)', () => {
       .expect({ message: 'Forbidden', statusCode: HttpStatus.FORBIDDEN });
   });
 
-  it('/v2/spaces/:space_uuid?profile_uuid={profile_uuid} (PATCH) profile not joined space', async () => {
+  it('/spaces/:space_uuid?profile_uuid={profile_uuid} (PATCH) profile not joined space', async () => {
     const newSpace = {
       name: 'new test space',
       icon: testImagePath,
@@ -447,7 +447,7 @@ describe('SpacesController (e2e)', () => {
     });
 
     return request(app.getHttpServer())
-      .patch(`/v2/spaces/${testSpace.uuid}?profile_uuid=${newProfile.uuid}`)
+      .patch(`/spaces/${testSpace.uuid}?profile_uuid=${newProfile.uuid}`)
       .auth(testToken, { type: 'bearer' })
       .field('name', newSpace.name)
       .attach('icon', newSpace.icon, { contentType: newSpace.iconContentType })
@@ -455,7 +455,7 @@ describe('SpacesController (e2e)', () => {
       .expect({ message: 'Forbidden', statusCode: HttpStatus.FORBIDDEN });
   });
 
-  it('/v2/spaces/:space_uuid?profile_uuid={profile_uuid} (PATCH) profile not found', () => {
+  it('/spaces/:space_uuid?profile_uuid={profile_uuid} (PATCH) profile not found', () => {
     const newSpace = {
       name: 'new test space',
       icon: testImagePath,
@@ -463,7 +463,7 @@ describe('SpacesController (e2e)', () => {
     };
 
     return request(app.getHttpServer())
-      .patch(`/v2/spaces/${testSpace.uuid}?profile_uuid=${uuid()}`)
+      .patch(`/spaces/${testSpace.uuid}?profile_uuid=${uuid()}`)
       .auth(testToken, { type: 'bearer' })
       .field('name', newSpace.name)
       .attach('icon', newSpace.icon, { contentType: newSpace.iconContentType })

From 7f5fcc061a4a801730bc1fe9f3e9c8e2b6c5b501 Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Sun, 6 Oct 2024 15:45:21 +0900
Subject: [PATCH 08/28] =?UTF-8?q?feat:=20=ED=94=84=EB=A1=9C=ED=95=84=20?=
 =?UTF-8?q?=EC=86=8C=EC=9C=A0=20=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 nestjs-BE/server/src/users/users.module.ts    |  3 +-
 .../server/src/users/users.service.spec.ts    | 47 +++++++++++++++++++
 nestjs-BE/server/src/users/users.service.ts   | 23 ++++++++-
 3 files changed, 70 insertions(+), 3 deletions(-)

diff --git a/nestjs-BE/server/src/users/users.module.ts b/nestjs-BE/server/src/users/users.module.ts
index acfee4ee..6fd5b2ad 100644
--- a/nestjs-BE/server/src/users/users.module.ts
+++ b/nestjs-BE/server/src/users/users.module.ts
@@ -2,9 +2,10 @@ import { Module } from '@nestjs/common';
 import { UsersService } from './users.service';
 import { UsersController } from './users.controller';
 import { PrismaModule } from '../prisma/prisma.module';
+import { ProfilesModule } from '../profiles/profiles.module';
 
 @Module({
-  imports: [PrismaModule],
+  imports: [PrismaModule, ProfilesModule],
   controllers: [UsersController],
   providers: [UsersService],
   exports: [UsersService],
diff --git a/nestjs-BE/server/src/users/users.service.spec.ts b/nestjs-BE/server/src/users/users.service.spec.ts
index 81f58428..c98fbd32 100644
--- a/nestjs-BE/server/src/users/users.service.spec.ts
+++ b/nestjs-BE/server/src/users/users.service.spec.ts
@@ -3,15 +3,22 @@ import { UsersService } from './users.service';
 import { PrismaService } from '../prisma/prisma.service';
 import { v4 as uuid } from 'uuid';
 import { KakaoUser, User } from '@prisma/client';
+import { ProfilesService } from '../profiles/profiles.service';
+import { ForbiddenException, NotFoundException } from '@nestjs/common';
 
 describe('UsersService', () => {
   let usersService: UsersService;
+  let profilesService: ProfilesService;
   let prisma: PrismaService;
 
   beforeEach(async () => {
     const module: TestingModule = await Test.createTestingModule({
       providers: [
         UsersService,
+        {
+          provide: ProfilesService,
+          useValue: { findProfileByProfileUuid: jest.fn() },
+        },
         {
           provide: PrismaService,
           useValue: {
@@ -24,6 +31,7 @@ describe('UsersService', () => {
     }).compile();
 
     usersService = module.get<UsersService>(UsersService);
+    profilesService = module.get<ProfilesService>(ProfilesService);
     prisma = module.get<PrismaService>(PrismaService);
   });
 
@@ -69,4 +77,43 @@ describe('UsersService', () => {
     expect(prisma.user.create).toHaveBeenCalled();
     expect(prisma.user.findUnique).not.toHaveBeenCalled();
   });
+
+  it('verifyUserProfile verified', async () => {
+    const userMock = { uuid: 'user uuid' };
+    const profileMock = { uuid: 'profile uuid', userUuid: userMock.uuid };
+
+    (profilesService.findProfileByProfileUuid as jest.Mock).mockResolvedValue(
+      profileMock,
+    );
+
+    const res = usersService.verifyUserProfile(userMock.uuid, profileMock.uuid);
+
+    await expect(res).resolves.toBeTruthy();
+  });
+
+  it('verifyUserProfile profile not found', async () => {
+    const userMock = { uuid: 'user uuid' };
+    const profileMock = { uuid: 'profile uuid', userUuid: userMock.uuid };
+
+    (profilesService.findProfileByProfileUuid as jest.Mock).mockResolvedValue(
+      null,
+    );
+
+    const res = usersService.verifyUserProfile(userMock.uuid, profileMock.uuid);
+
+    await expect(res).rejects.toThrow(NotFoundException);
+  });
+
+  it('verifyUserProfile profile user not own', async () => {
+    const userMock = { uuid: 'user uuid' };
+    const profileMock = { uuid: 'profile uuid', userUuid: 'other user uuid' };
+
+    (profilesService.findProfileByProfileUuid as jest.Mock).mockResolvedValue(
+      profileMock,
+    );
+
+    const res = usersService.verifyUserProfile(userMock.uuid, profileMock.uuid);
+
+    await expect(res).rejects.toThrow(ForbiddenException);
+  });
 });
diff --git a/nestjs-BE/server/src/users/users.service.ts b/nestjs-BE/server/src/users/users.service.ts
index e68104eb..133c2e9d 100644
--- a/nestjs-BE/server/src/users/users.service.ts
+++ b/nestjs-BE/server/src/users/users.service.ts
@@ -1,12 +1,20 @@
-import { Injectable } from '@nestjs/common';
+import {
+  ForbiddenException,
+  Injectable,
+  NotFoundException,
+} from '@nestjs/common';
 import { PrismaService } from '../prisma/prisma.service';
 import { CreateUserPrismaDto } from './dto/create-user.dto';
 import { Space, User } from '@prisma/client';
 import { v4 as uuid } from 'uuid';
+import { ProfilesService } from '../profiles/profiles.service';
 
 @Injectable()
 export class UsersService {
-  constructor(private prisma: PrismaService) {}
+  constructor(
+    private readonly prisma: PrismaService,
+    private readonly profilesService: ProfilesService,
+  ) {}
 
   async getOrCreateUser(data: CreateUserPrismaDto): Promise<User> {
     return this.prisma.$transaction(async () => {
@@ -43,4 +51,15 @@ export class UsersService {
 
     return spaces;
   }
+
+  async verifyUserProfile(
+    userUuid: string,
+    profileUuid: string,
+  ): Promise<boolean> {
+    const profile =
+      await this.profilesService.findProfileByProfileUuid(profileUuid);
+    if (!profile) throw new NotFoundException();
+    if (userUuid !== profile.userUuid) throw new ForbiddenException();
+    return true;
+  }
 }

From 43138bb6f20e921c5f8c949ff3dcd5c39e1cd899 Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Sun, 6 Oct 2024 16:16:30 +0900
Subject: [PATCH 09/28] =?UTF-8?q?refactor:=20=EC=9C=A0=EC=A0=80=20?=
 =?UTF-8?q?=ED=94=84=EB=A1=9C=ED=95=84=20=EA=B2=80=EC=A6=9D=20=EB=B6=80?=
 =?UTF-8?q?=EB=B6=84=20=EA=B5=90=EC=B2=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/spaces/spaces.controller.spec.ts      | 76 +++++++------------
 .../server/src/spaces/spaces.controller.ts    | 30 +++-----
 nestjs-BE/server/src/spaces/spaces.module.ts  |  4 +-
 3 files changed, 38 insertions(+), 72 deletions(-)

diff --git a/nestjs-BE/server/src/spaces/spaces.controller.spec.ts b/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
index bff5fa59..5dcb5eec 100644
--- a/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
+++ b/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
@@ -3,7 +3,6 @@ import { SpacesController } from './spaces.controller';
 import { SpacesService } from './spaces.service';
 import { ProfileSpaceService } from '../profile-space/profile-space.service';
 import { UploadService } from '../upload/upload.service';
-import { ProfilesService } from '../profiles/profiles.service';
 import { Profile, Space } from '@prisma/client';
 import {
   BadRequestException,
@@ -15,14 +14,15 @@ import { UpdateSpaceRequestDto } from './dto/update-space.dto';
 import { CreateSpaceRequestDto } from './dto/create-space.dto';
 import { RequestWithUser } from '../utils/interface';
 import { ConfigModule, ConfigService } from '@nestjs/config';
+import { UsersService } from '../users/users.service';
 
 describe('SpacesController', () => {
   let controller: SpacesController;
   let spacesService: SpacesService;
   let uploadService: UploadService;
-  let profilesService: ProfilesService;
   let configService: ConfigService;
   let profileSpaceService: ProfileSpaceService;
+  let usersService: UsersService;
 
   beforeEach(async () => {
     const module: TestingModule = await Test.createTestingModule({
@@ -45,22 +45,16 @@ describe('SpacesController', () => {
             joinSpace: jest.fn(),
           },
         },
-        {
-          provide: ProfilesService,
-          useValue: {
-            findProfile: jest.fn(),
-            findProfileByProfileUuid: jest.fn(),
-          },
-        },
+        { provide: UsersService, useValue: { verifyUserProfile: jest.fn() } },
       ],
     }).compile();
 
     controller = module.get<SpacesController>(SpacesController);
     spacesService = module.get<SpacesService>(SpacesService);
     uploadService = module.get<UploadService>(UploadService);
-    profilesService = module.get<ProfilesService>(ProfilesService);
     configService = module.get<ConfigService>(ConfigService);
     profileSpaceService = module.get<ProfileSpaceService>(ProfileSpaceService);
+    usersService = module.get<UsersService>(UsersService);
   });
 
   it('create created', async () => {
@@ -77,9 +71,7 @@ describe('SpacesController', () => {
     } as CreateSpaceRequestDto;
     const spaceMock = { uuid: 'space uuid' } as Space;
 
-    jest
-      .spyOn(profilesService, 'findProfileByProfileUuid')
-      .mockResolvedValue(profileMock);
+    jest.spyOn(usersService, 'verifyUserProfile').mockResolvedValue(true);
     jest.spyOn(uploadService, 'uploadFile').mockResolvedValue(iconUrlMock);
     jest.spyOn(spacesService, 'createSpace').mockResolvedValue(spaceMock);
 
@@ -107,8 +99,8 @@ describe('SpacesController', () => {
     const requestMock = { user: { uuid: 'user uuid' } } as RequestWithUser;
 
     jest
-      .spyOn(profilesService, 'findProfileByProfileUuid')
-      .mockResolvedValue(null);
+      .spyOn(usersService, 'verifyUserProfile')
+      .mockRejectedValue(new NotFoundException());
 
     const response = controller.create(iconMock, bodyMock, requestMock);
 
@@ -130,8 +122,8 @@ describe('SpacesController', () => {
     } as CreateSpaceRequestDto;
 
     jest
-      .spyOn(profilesService, 'findProfileByProfileUuid')
-      .mockResolvedValue(profileMock);
+      .spyOn(usersService, 'verifyUserProfile')
+      .mockRejectedValue(new ForbiddenException());
 
     const response = controller.create(iconMock, bodyMock, requestMock);
 
@@ -152,9 +144,7 @@ describe('SpacesController', () => {
     } as CreateSpaceRequestDto;
     const spaceMock = { uuid: 'space uuid' } as Space;
 
-    jest
-      .spyOn(profilesService, 'findProfileByProfileUuid')
-      .mockResolvedValue(profileMock);
+    jest.spyOn(usersService, 'verifyUserProfile').mockResolvedValue(true);
     jest.spyOn(spacesService, 'createSpace').mockResolvedValue(spaceMock);
 
     const response = controller.create(
@@ -188,9 +178,7 @@ describe('SpacesController', () => {
       profileUuid: profileMock.uuid,
     };
 
-    jest
-      .spyOn(profilesService, 'findProfileByProfileUuid')
-      .mockResolvedValue(profileMock);
+    jest.spyOn(usersService, 'verifyUserProfile').mockResolvedValue(true);
     jest.spyOn(spacesService, 'findSpace').mockResolvedValue(spaceMock);
     jest
       .spyOn(profileSpaceService, 'findProfileSpaceByBothUuid')
@@ -216,7 +204,7 @@ describe('SpacesController', () => {
     const response = controller.findOne(spaceMock.uuid, undefined, requestMock);
 
     await expect(response).rejects.toThrow(BadRequestException);
-    expect(profilesService.findProfileByProfileUuid).not.toHaveBeenCalled();
+    expect(usersService.verifyUserProfile).not.toHaveBeenCalled();
   });
 
   it("findOne profile user doesn't have", async () => {
@@ -228,8 +216,8 @@ describe('SpacesController', () => {
     } as Profile;
 
     jest
-      .spyOn(profilesService, 'findProfileByProfileUuid')
-      .mockResolvedValue(profileMock);
+      .spyOn(usersService, 'verifyUserProfile')
+      .mockRejectedValue(new ForbiddenException());
 
     const response = controller.findOne(
       spaceMock.uuid,
@@ -249,9 +237,7 @@ describe('SpacesController', () => {
       userUuid: requestMock.user.uuid,
     } as Profile;
 
-    jest
-      .spyOn(profilesService, 'findProfileByProfileUuid')
-      .mockResolvedValue(profileMock);
+    jest.spyOn(usersService, 'verifyUserProfile').mockResolvedValue(true);
     jest.spyOn(spacesService, 'findSpace').mockResolvedValue(spaceMock);
     jest
       .spyOn(profileSpaceService, 'findProfileSpaceByBothUuid')
@@ -274,9 +260,7 @@ describe('SpacesController', () => {
       userUuid: requestMock.user.uuid,
     } as Profile;
 
-    jest
-      .spyOn(profilesService, 'findProfileByProfileUuid')
-      .mockResolvedValue(profileMock);
+    jest.spyOn(usersService, 'verifyUserProfile').mockResolvedValue(true);
     jest.spyOn(spacesService, 'findSpace').mockResolvedValue(null);
 
     const response = controller.findOne(
@@ -297,8 +281,8 @@ describe('SpacesController', () => {
     } as Profile;
 
     jest
-      .spyOn(profilesService, 'findProfileByProfileUuid')
-      .mockResolvedValue(null);
+      .spyOn(usersService, 'verifyUserProfile')
+      .mockRejectedValue(new NotFoundException());
 
     const response = controller.findOne(
       spaceMock.uuid,
@@ -324,9 +308,7 @@ describe('SpacesController', () => {
       profileUuid: profileMock.uuid,
     };
 
-    jest
-      .spyOn(profilesService, 'findProfileByProfileUuid')
-      .mockResolvedValue(profileMock);
+    jest.spyOn(usersService, 'verifyUserProfile').mockResolvedValue(true);
     jest
       .spyOn(profileSpaceService, 'findProfileSpaceByBothUuid')
       .mockResolvedValue(profileSpaceMock);
@@ -366,9 +348,7 @@ describe('SpacesController', () => {
       profileUuid: profileMock.uuid,
     };
 
-    jest
-      .spyOn(profilesService, 'findProfileByProfileUuid')
-      .mockResolvedValue(profileMock);
+    jest.spyOn(usersService, 'verifyUserProfile').mockResolvedValue(true);
     jest
       .spyOn(profileSpaceService, 'findProfileSpaceByBothUuid')
       .mockResolvedValue(profileSpaceMock);
@@ -408,9 +388,7 @@ describe('SpacesController', () => {
       profileUuid: profileMock.uuid,
     };
 
-    jest
-      .spyOn(profilesService, 'findProfileByProfileUuid')
-      .mockResolvedValue(profileMock);
+    jest.spyOn(usersService, 'verifyUserProfile').mockResolvedValue(true);
     jest
       .spyOn(profileSpaceService, 'findProfileSpaceByBothUuid')
       .mockResolvedValue(profileSpaceMock);
@@ -447,8 +425,8 @@ describe('SpacesController', () => {
     const bodyMock = { name: 'new space name' } as UpdateSpaceRequestDto;
 
     jest
-      .spyOn(profilesService, 'findProfileByProfileUuid')
-      .mockResolvedValue(profileMock);
+      .spyOn(usersService, 'verifyUserProfile')
+      .mockRejectedValue(new ForbiddenException());
 
     const response = controller.update(
       iconMock,
@@ -473,9 +451,7 @@ describe('SpacesController', () => {
     } as Profile;
     const bodyMock = { name: 'new space name' } as UpdateSpaceRequestDto;
 
-    jest
-      .spyOn(profilesService, 'findProfileByProfileUuid')
-      .mockResolvedValue(profileMock);
+    jest.spyOn(usersService, 'verifyUserProfile').mockResolvedValue(true);
     jest
       .spyOn(profileSpaceService, 'findProfileSpaceByBothUuid')
       .mockResolvedValue(null);
@@ -504,8 +480,8 @@ describe('SpacesController', () => {
     const bodyMock = { name: 'new space name' } as UpdateSpaceRequestDto;
 
     jest
-      .spyOn(profilesService, 'findProfileByProfileUuid')
-      .mockResolvedValue(null);
+      .spyOn(usersService, 'verifyUserProfile')
+      .mockRejectedValue(new NotFoundException());
 
     const response = controller.update(
       iconMock,
diff --git a/nestjs-BE/server/src/spaces/spaces.controller.ts b/nestjs-BE/server/src/spaces/spaces.controller.ts
index 9ac17081..b2ad19b8 100644
--- a/nestjs-BE/server/src/spaces/spaces.controller.ts
+++ b/nestjs-BE/server/src/spaces/spaces.controller.ts
@@ -24,8 +24,8 @@ import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger';
 import { UploadService } from '../upload/upload.service';
 import { ProfileSpaceService } from '../profile-space/profile-space.service';
 import { RequestWithUser } from '../utils/interface';
-import { ProfilesService } from '../profiles/profiles.service';
 import { ConfigService } from '@nestjs/config';
+import { UsersService } from '../users/users.service';
 
 @Controller('spaces')
 @ApiTags('spaces')
@@ -34,8 +34,8 @@ export class SpacesController {
     private readonly spacesService: SpacesService,
     private readonly uploadService: UploadService,
     private readonly profileSpaceService: ProfileSpaceService,
-    private readonly profilesService: ProfilesService,
     private readonly configService: ConfigService,
+    private readonly usersService: UsersService,
   ) {}
 
   @Post()
@@ -74,19 +74,19 @@ export class SpacesController {
     @Req() req: RequestWithUser,
   ) {
     if (!createSpaceDto.profileUuid) throw new BadRequestException();
-    const profile = await this.profilesService.findProfileByProfileUuid(
+    await this.usersService.verifyUserProfile(
+      req.user.uuid,
       createSpaceDto.profileUuid,
     );
-    if (!profile) throw new NotFoundException();
-    if (req.user.uuid !== profile.userUuid) {
-      throw new ForbiddenException();
-    }
     const iconUrl = icon
       ? await this.uploadService.uploadFile(icon)
       : this.configService.get<string>('APP_ICON_URL');
     createSpaceDto.icon = iconUrl;
     const space = await this.spacesService.createSpace(createSpaceDto);
-    await this.profileSpaceService.joinSpace(profile.uuid, space.uuid);
+    await this.profileSpaceService.joinSpace(
+      createSpaceDto.profileUuid,
+      space.uuid,
+    );
     return { statusCode: HttpStatus.CREATED, message: 'Created', data: space };
   }
 
@@ -119,12 +119,7 @@ export class SpacesController {
     @Req() req: RequestWithUser,
   ) {
     if (!profileUuid) throw new BadRequestException();
-    const profile =
-      await this.profilesService.findProfileByProfileUuid(profileUuid);
-    if (!profile) throw new NotFoundException();
-    if (req.user.uuid !== profile.userUuid) {
-      throw new ForbiddenException();
-    }
+    await this.usersService.verifyUserProfile(req.user.uuid, profileUuid);
     const space = await this.spacesService.findSpace(spaceUuid);
     if (!space) throw new NotFoundException();
     const profileSpace =
@@ -168,12 +163,7 @@ export class SpacesController {
     @Req() req: RequestWithUser,
   ) {
     if (!profileUuid) throw new BadRequestException();
-    const profile =
-      await this.profilesService.findProfileByProfileUuid(profileUuid);
-    if (!profile) throw new NotFoundException();
-    if (req.user.uuid !== profile.userUuid) {
-      throw new ForbiddenException();
-    }
+    await this.usersService.verifyUserProfile(req.user.uuid, profileUuid);
     const profileSpace =
       await this.profileSpaceService.findProfileSpaceByBothUuid(
         profileUuid,
diff --git a/nestjs-BE/server/src/spaces/spaces.module.ts b/nestjs-BE/server/src/spaces/spaces.module.ts
index 52c1bf25..3bd19f1d 100644
--- a/nestjs-BE/server/src/spaces/spaces.module.ts
+++ b/nestjs-BE/server/src/spaces/spaces.module.ts
@@ -3,10 +3,10 @@ import { SpacesService } from './spaces.service';
 import { SpacesController } from './spaces.controller';
 import { UploadModule } from '../upload/upload.module';
 import { ProfileSpaceModule } from '../profile-space/profile-space.module';
-import { ProfilesModule } from '../profiles/profiles.module';
+import { UsersModule } from '../users/users.module';
 
 @Module({
-  imports: [forwardRef(() => ProfileSpaceModule), ProfilesModule, UploadModule],
+  imports: [forwardRef(() => ProfileSpaceModule), UploadModule, UsersModule],
   controllers: [SpacesController],
   providers: [SpacesService],
   exports: [SpacesService],

From 9decbf613699fbe71d99bc3b683367fe00e81005 Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Sun, 6 Oct 2024 17:57:37 +0900
Subject: [PATCH 10/28] =?UTF-8?q?refactor:=20mocking=20=EB=B0=A9=EC=8B=9D?=
 =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../server/src/spaces/spaces.service.spec.ts  | 21 ++++++++++---------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/nestjs-BE/server/src/spaces/spaces.service.spec.ts b/nestjs-BE/server/src/spaces/spaces.service.spec.ts
index 4efe6e2a..4c508469 100644
--- a/nestjs-BE/server/src/spaces/spaces.service.spec.ts
+++ b/nestjs-BE/server/src/spaces/spaces.service.spec.ts
@@ -25,7 +25,8 @@ describe('SpacesService', () => {
   it('updateSpace updated space', async () => {
     const data = { name: 'new space name', icon: 'new space icon' };
     const spaceMock = { uuid: 'space uuid', ...data };
-    jest.spyOn(prisma.space, 'update').mockResolvedValue(spaceMock);
+
+    (prisma.space.update as jest.Mock).mockResolvedValue(spaceMock);
 
     const space = spacesService.updateSpace('space uuid', data);
 
@@ -34,14 +35,13 @@ describe('SpacesService', () => {
 
   it('updateSpace fail', async () => {
     const data = { name: 'new space name', icon: 'new space icon' };
-    jest
-      .spyOn(prisma.space, 'update')
-      .mockRejectedValue(
-        new PrismaClientKnownRequestError(
-          'An operation failed because it depends on one or more records that were required but not found. Record to update not found.',
-          { code: 'P2025', clientVersion: '' },
-        ),
-      );
+
+    (prisma.space.update as jest.Mock).mockRejectedValue(
+      new PrismaClientKnownRequestError('', {
+        code: 'P2025',
+        clientVersion: '',
+      }),
+    );
 
     const space = spacesService.updateSpace('space uuid', data);
 
@@ -50,7 +50,8 @@ describe('SpacesService', () => {
 
   it('updateSpace fail', async () => {
     const data = { name: 'new space name', icon: 'new space icon' };
-    jest.spyOn(prisma.space, 'update').mockRejectedValue(new Error());
+
+    (prisma.space.update as jest.Mock).mockRejectedValue(new Error());
 
     const space = spacesService.updateSpace('space uuid', data);
 

From dc0f1e2db9c0395c9030a2b5c3c4e78d6fa22c0f Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Sun, 6 Oct 2024 18:53:33 +0900
Subject: [PATCH 11/28] =?UTF-8?q?feat:=20=EC=8A=A4=ED=8E=98=EC=9D=B4?=
 =?UTF-8?q?=EC=8A=A4=20=EA=B4=80=EB=A0=A8=20=EB=8F=99=EC=9E=91=20=EC=84=9C?=
 =?UTF-8?q?=EB=B9=84=EC=8A=A4=EB=A1=9C=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../profile-space/profile-space.service.ts    |  18 ++
 .../server/src/spaces/spaces.service.spec.ts  | 213 +++++++++++++++++-
 nestjs-BE/server/src/spaces/spaces.service.ts |  78 ++++++-
 3 files changed, 305 insertions(+), 4 deletions(-)

diff --git a/nestjs-BE/server/src/profile-space/profile-space.service.ts b/nestjs-BE/server/src/profile-space/profile-space.service.ts
index 55c6c1da..a1e4769e 100644
--- a/nestjs-BE/server/src/profile-space/profile-space.service.ts
+++ b/nestjs-BE/server/src/profile-space/profile-space.service.ts
@@ -6,6 +6,24 @@ import { Prisma, ProfileSpace } from '@prisma/client';
 export class ProfileSpaceService {
   constructor(private readonly prisma: PrismaService) {}
 
+  async createProfileSpace(
+    profileUuid: string,
+    spaceUuid: string,
+  ): Promise<ProfileSpace | null> {
+    return this.prisma.profileSpace.create({
+      data: { spaceUuid, profileUuid },
+    });
+  }
+
+  async deleteProfileSpace(
+    profileUuid: string,
+    spaceUuid: string,
+  ): Promise<ProfileSpace | null> {
+    return this.prisma.profileSpace.delete({
+      where: { spaceUuid_profileUuid: { spaceUuid, profileUuid } },
+    });
+  }
+
   async findProfileSpacesByProfileUuid(
     profileUuid: string,
   ): Promise<ProfileSpace[]> {
diff --git a/nestjs-BE/server/src/spaces/spaces.service.spec.ts b/nestjs-BE/server/src/spaces/spaces.service.spec.ts
index 4c508469..42f43896 100644
--- a/nestjs-BE/server/src/spaces/spaces.service.spec.ts
+++ b/nestjs-BE/server/src/spaces/spaces.service.spec.ts
@@ -1,11 +1,20 @@
+import {
+  ConflictException,
+  ForbiddenException,
+  NotFoundException,
+} from '@nestjs/common';
 import { Test, TestingModule } from '@nestjs/testing';
 import { SpacesService } from './spaces.service';
 import { PrismaService } from '../prisma/prisma.service';
 import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library';
+import { ProfileSpaceService } from '../profile-space/profile-space.service';
+import { UsersService } from '../users/users.service';
 
 describe('SpacesService', () => {
   let spacesService: SpacesService;
   let prisma: PrismaService;
+  let profileSpaceService: ProfileSpaceService;
+  let usersService: UsersService;
 
   beforeEach(async () => {
     const module: TestingModule = await Test.createTestingModule({
@@ -13,13 +22,30 @@ describe('SpacesService', () => {
         SpacesService,
         {
           provide: PrismaService,
-          useValue: { space: { update: jest.fn() } },
+          useValue: {
+            space: { update: jest.fn() },
+            profile: { findMany: jest.fn() },
+          },
+        },
+        {
+          provide: ProfileSpaceService,
+          useValue: {
+            createProfileSpace: jest.fn(),
+            deleteProfileSpace: jest.fn(),
+            isSpaceEmpty: jest.fn(),
+          },
+        },
+        {
+          provide: UsersService,
+          useValue: { verifyUserProfile: jest.fn() },
         },
       ],
     }).compile();
 
     spacesService = module.get<SpacesService>(SpacesService);
     prisma = module.get<PrismaService>(PrismaService);
+    profileSpaceService = module.get<ProfileSpaceService>(ProfileSpaceService);
+    usersService = module.get<UsersService>(UsersService);
   });
 
   it('updateSpace updated space', async () => {
@@ -57,4 +83,189 @@ describe('SpacesService', () => {
 
     await expect(space).rejects.toThrow(Error);
   });
+
+  it('joinSpace', async () => {
+    const userUuid = 'user uuid';
+    const profileUuid = 'profile uuid';
+    const spaceUuid = 'space uuid';
+
+    const res = spacesService.joinSpace(userUuid, profileUuid, spaceUuid);
+
+    await expect(res).resolves.toBeUndefined();
+  });
+
+  it('joinSpace profile not found', async () => {
+    const userUuid = 'user uuid';
+    const profileUuid = 'profile uuid';
+    const spaceUuid = 'space uuid';
+
+    (usersService.verifyUserProfile as jest.Mock).mockRejectedValue(
+      new NotFoundException(),
+    );
+
+    const res = spacesService.joinSpace(userUuid, profileUuid, spaceUuid);
+
+    await expect(res).rejects.toThrow(NotFoundException);
+  });
+
+  it('joinSpace profile user not own', async () => {
+    const userUuid = 'user uuid';
+    const profileUuid = 'profile uuid';
+    const spaceUuid = 'space uuid';
+
+    (usersService.verifyUserProfile as jest.Mock).mockRejectedValue(
+      new ForbiddenException(),
+    );
+
+    const res = spacesService.joinSpace(userUuid, profileUuid, spaceUuid);
+
+    await expect(res).rejects.toThrow(ForbiddenException);
+  });
+
+  it('joinSpace conflict', async () => {
+    const userUuid = 'user uuid';
+    const profileUuid = 'profile uuid';
+    const spaceUuid = 'space uuid';
+
+    (profileSpaceService.createProfileSpace as jest.Mock).mockRejectedValue(
+      new PrismaClientKnownRequestError('', {
+        code: 'P2002',
+        clientVersion: '',
+      }),
+    );
+
+    const res = spacesService.joinSpace(userUuid, profileUuid, spaceUuid);
+
+    await expect(res).rejects.toThrow(ConflictException);
+  });
+
+  it('joinSpace space not found', async () => {
+    const userUuid = 'user uuid';
+    const profileUuid = 'profile uuid';
+    const spaceUuid = 'space uuid';
+
+    (profileSpaceService.createProfileSpace as jest.Mock).mockRejectedValue(
+      new PrismaClientKnownRequestError('', {
+        code: 'P2003',
+        clientVersion: '',
+      }),
+    );
+
+    const res = spacesService.joinSpace(userUuid, profileUuid, spaceUuid);
+
+    await expect(res).rejects.toThrow(ForbiddenException);
+  });
+
+  it('leaveSpace', async () => {
+    const userUuid = 'user uuid';
+    const profileUuid = 'profile uuid';
+    const spaceUuid = 'space uuid';
+
+    jest.spyOn(spacesService, 'deleteSpace').mockResolvedValue(null);
+
+    const res = spacesService.leaveSpace(userUuid, profileUuid, spaceUuid);
+
+    await expect(res).resolves.toBeUndefined();
+  });
+
+  it('leaveSpace space delete fail', async () => {
+    const userUuid = 'user uuid';
+    const profileUuid = 'profile uuid';
+    const spaceUuid = 'space uuid';
+
+    jest.spyOn(spacesService, 'deleteSpace').mockRejectedValue(
+      new PrismaClientKnownRequestError('', {
+        code: 'P2025',
+        clientVersion: '',
+      }),
+    );
+
+    const res = spacesService.leaveSpace(userUuid, profileUuid, spaceUuid);
+
+    await expect(res).resolves.toBeUndefined();
+  });
+
+  it('leaveSpace profile not found', async () => {
+    const userUuid = 'user uuid';
+    const profileUuid = 'profile uuid';
+    const spaceUuid = 'space uuid';
+
+    (usersService.verifyUserProfile as jest.Mock).mockRejectedValue(
+      new NotFoundException(),
+    );
+    jest.spyOn(spacesService, 'deleteSpace').mockResolvedValue(null);
+
+    const res = spacesService.leaveSpace(userUuid, profileUuid, spaceUuid);
+
+    await expect(res).rejects.toThrow(NotFoundException);
+  });
+
+  it('leaveSpace profile user not own', async () => {
+    const userUuid = 'user uuid';
+    const profileUuid = 'profile uuid';
+    const spaceUuid = 'space uuid';
+
+    (usersService.verifyUserProfile as jest.Mock).mockRejectedValue(
+      new ForbiddenException(),
+    );
+    jest.spyOn(spacesService, 'deleteSpace').mockResolvedValue(null);
+
+    const res = spacesService.leaveSpace(userUuid, profileUuid, spaceUuid);
+
+    await expect(res).rejects.toThrow(ForbiddenException);
+  });
+
+  it('leaveSpace profileSpace not found', async () => {
+    const userUuid = 'user uuid';
+    const profileUuid = 'profile uuid';
+    const spaceUuid = 'space uuid';
+
+    (profileSpaceService.deleteProfileSpace as jest.Mock).mockRejectedValue(
+      new PrismaClientKnownRequestError('', {
+        code: 'P2025',
+        clientVersion: '',
+      }),
+    );
+    jest.spyOn(spacesService, 'deleteSpace').mockResolvedValue(null);
+
+    const res = spacesService.leaveSpace(userUuid, profileUuid, spaceUuid);
+
+    await expect(res).rejects.toThrow(NotFoundException);
+  });
+
+  it('findProfilesInSpace profile not found', async () => {
+    const userUuid = 'user uuid';
+    const profileUuid = 'profile uuid';
+    const spaceUuid = 'space uuid';
+
+    (usersService.verifyUserProfile as jest.Mock).mockRejectedValue(
+      new NotFoundException(),
+    );
+
+    const res = spacesService.findProfilesInSpace(
+      userUuid,
+      profileUuid,
+      spaceUuid,
+    );
+
+    await expect(res).rejects.toThrow(NotFoundException);
+  });
+
+  it('findProfilesInSpace profile user not own', async () => {
+    const userUuid = 'user uuid';
+    const profileUuid = 'profile uuid';
+    const spaceUuid = 'space uuid';
+
+    (usersService.verifyUserProfile as jest.Mock).mockRejectedValue(
+      new ForbiddenException(),
+    );
+
+    const res = spacesService.findProfilesInSpace(
+      userUuid,
+      profileUuid,
+      spaceUuid,
+    );
+
+    await expect(res).rejects.toThrow(ForbiddenException);
+  });
 });
diff --git a/nestjs-BE/server/src/spaces/spaces.service.ts b/nestjs-BE/server/src/spaces/spaces.service.ts
index e2b200a0..47bd1cf6 100644
--- a/nestjs-BE/server/src/spaces/spaces.service.ts
+++ b/nestjs-BE/server/src/spaces/spaces.service.ts
@@ -1,13 +1,24 @@
-import { Injectable } from '@nestjs/common';
+import {
+  ConflictException,
+  ForbiddenException,
+  Injectable,
+  NotFoundException,
+} from '@nestjs/common';
 import { PrismaService } from '../prisma/prisma.service';
 import { UpdateSpacePrismaDto } from './dto/update-space.dto';
-import { Prisma, Space } from '@prisma/client';
+import { Prisma, Profile, Space } from '@prisma/client';
 import { CreateSpacePrismaDto } from './dto/create-space.dto';
 import { v4 as uuid } from 'uuid';
+import { ProfileSpaceService } from '../profile-space/profile-space.service';
+import { UsersService } from '../users/users.service';
 
 @Injectable()
 export class SpacesService {
-  constructor(protected prisma: PrismaService) {}
+  constructor(
+    private readonly prisma: PrismaService,
+    private readonly profileSpaceService: ProfileSpaceService,
+    private readonly usersService: UsersService,
+  ) {}
 
   async findSpace(spaceUuid: string): Promise<Space | null> {
     return this.prisma.space.findUnique({ where: { uuid: spaceUuid } });
@@ -48,4 +59,65 @@ export class SpacesService {
   async deleteSpace(spaceUuid: string): Promise<Space> {
     return this.prisma.space.delete({ where: { uuid: spaceUuid } });
   }
+
+  async joinSpace(
+    userUuid: string,
+    profileUuid: string,
+    spaceUuid: string,
+  ): Promise<void> {
+    await this.usersService.verifyUserProfile(userUuid, profileUuid);
+    try {
+      await this.profileSpaceService.createProfileSpace(profileUuid, spaceUuid);
+    } catch (err) {
+      if (err instanceof Prisma.PrismaClientKnownRequestError) {
+        switch (err.code) {
+          case 'P2002':
+            throw new ConflictException();
+          case 'P2003':
+            throw new ForbiddenException();
+          default:
+            throw err;
+        }
+      } else {
+        throw err;
+      }
+    }
+  }
+
+  async leaveSpace(
+    userUuid: string,
+    profileUuid: string,
+    spaceUuid: string,
+  ): Promise<void> {
+    await this.usersService.verifyUserProfile(userUuid, profileUuid);
+    try {
+      await this.profileSpaceService.deleteProfileSpace(profileUuid, spaceUuid);
+    } catch (err) {
+      if (err instanceof Prisma.PrismaClientKnownRequestError) {
+        switch (err.code) {
+          case 'P2025':
+            throw new NotFoundException();
+          default:
+            throw err;
+        }
+      } else {
+        throw err;
+      }
+    }
+    const isSpaceEmpty = await this.profileSpaceService.isSpaceEmpty(spaceUuid);
+    try {
+      if (!isSpaceEmpty) await this.deleteSpace(spaceUuid);
+    } catch (err) {}
+  }
+
+  async findProfilesInSpace(
+    userUuid: string,
+    profileUuid: string,
+    spaceUuid: string,
+  ): Promise<Profile[]> {
+    await this.usersService.verifyUserProfile(userUuid, profileUuid);
+    return this.prisma.profile.findMany({
+      where: { spaces: { some: { spaceUuid } } },
+    });
+  }
 }

From cad896f792e60547873901f43b7997a6d7ed9da4 Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Sun, 6 Oct 2024 20:10:15 +0900
Subject: [PATCH 12/28] =?UTF-8?q?refactor:=20=EB=B9=84=EB=8F=99=EA=B8=B0?=
 =?UTF-8?q?=20=EB=8F=99=EC=9E=91=20=EA=B0=9C=EC=84=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 nestjs-BE/server/test/users.e2e-spec.ts | 24 ++++++++++--------------
 1 file changed, 10 insertions(+), 14 deletions(-)

diff --git a/nestjs-BE/server/test/users.e2e-spec.ts b/nestjs-BE/server/test/users.e2e-spec.ts
index 1f55a7a5..c3d1955f 100644
--- a/nestjs-BE/server/test/users.e2e-spec.ts
+++ b/nestjs-BE/server/test/users.e2e-spec.ts
@@ -64,20 +64,16 @@ describe('UsersController (e2e)', () => {
       },
     });
     const spacePromises = Array.from({ length: SPACE_NUMBER }, async () => {
-      return prisma.space
-        .create({
-          data: { uuid: uuid(), name: 'test space', icon: 'test icon' },
-        })
-        .then(async (space) => {
-          return prisma.profileSpace
-            .create({
-              data: {
-                profileUuid: profile.uuid,
-                spaceUuid: space.uuid,
-              },
-            })
-            .then(() => space);
-        });
+      const space = await prisma.space.create({
+        data: { uuid: uuid(), name: 'test space', icon: 'test icon' },
+      });
+      await prisma.profileSpace.create({
+        data: {
+          profileUuid: profile.uuid,
+          spaceUuid: space.uuid,
+        },
+      });
+      return space;
     });
     const spaces = await Promise.all(spacePromises);
 

From c892ca55a6faa97e6acd546ccb2309259ba335b3 Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Sun, 6 Oct 2024 20:35:40 +0900
Subject: [PATCH 13/28] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?=
 =?UTF-8?q?=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../profile-space.service.spec.ts             | 46 +++++++++++++++++++
 1 file changed, 46 insertions(+)
 create mode 100644 nestjs-BE/server/src/profile-space/profile-space.service.spec.ts

diff --git a/nestjs-BE/server/src/profile-space/profile-space.service.spec.ts b/nestjs-BE/server/src/profile-space/profile-space.service.spec.ts
new file mode 100644
index 00000000..df6aefae
--- /dev/null
+++ b/nestjs-BE/server/src/profile-space/profile-space.service.spec.ts
@@ -0,0 +1,46 @@
+import { Test, TestingModule } from '@nestjs/testing';
+import { ProfileSpaceService } from './profile-space.service';
+import { PrismaService } from '../prisma/prisma.service';
+
+describe('ProfileSpaceService', () => {
+  let profileSpaceService: ProfileSpaceService;
+  let prisma: PrismaService;
+
+  beforeEach(async () => {
+    const module: TestingModule = await Test.createTestingModule({
+      providers: [
+        ProfileSpaceService,
+        {
+          provide: PrismaService,
+          useValue: { profileSpace: { findFirst: jest.fn() } },
+        },
+      ],
+    }).compile();
+
+    profileSpaceService = module.get<ProfileSpaceService>(ProfileSpaceService);
+    prisma = module.get<PrismaService>(PrismaService);
+  });
+
+  it('isSpaceEmpty empty', async () => {
+    const spaceUuid = 'space uuid';
+
+    (prisma.profileSpace.findFirst as jest.Mock).mockResolvedValue(null);
+
+    const isSpaceEmpty = profileSpaceService.isSpaceEmpty(spaceUuid);
+
+    await expect(isSpaceEmpty).resolves.toBeTruthy();
+  });
+
+  it('isSpaceEmpty not empty', async () => {
+    const spaceUuid = 'space uuid';
+    const profileSpace = 'profile space';
+
+    (prisma.profileSpace.findFirst as jest.Mock).mockResolvedValue(
+      profileSpace,
+    );
+
+    const isSpaceEmpty = profileSpaceService.isSpaceEmpty(spaceUuid);
+
+    await expect(isSpaceEmpty).resolves.toBeFalsy();
+  });
+});

From 74081fe4f47985e7f16b6618d950716e5e4ddcc6 Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Sun, 6 Oct 2024 20:37:55 +0900
Subject: [PATCH 14/28] =?UTF-8?q?remove:=20=EB=B6=88=ED=95=84=EC=9A=94=20?=
 =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EC=82=AD=EC=A0=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../server/src/profiles/dto/profile-space.dto.ts     | 12 ------------
 1 file changed, 12 deletions(-)
 delete mode 100644 nestjs-BE/server/src/profiles/dto/profile-space.dto.ts

diff --git a/nestjs-BE/server/src/profiles/dto/profile-space.dto.ts b/nestjs-BE/server/src/profiles/dto/profile-space.dto.ts
deleted file mode 100644
index 19fad8d4..00000000
--- a/nestjs-BE/server/src/profiles/dto/profile-space.dto.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { ApiProperty } from '@nestjs/swagger';
-
-export class ProfileSpaceDto {
-  @ApiProperty({
-    example: 'profile-uuid-123',
-    description: 'UUID of the profile',
-  })
-  profile_uuid: string;
-
-  @ApiProperty({ example: 'space-uuid-456', description: 'UUID of the space' })
-  space_uuid: string;
-}

From 3fa19bf1fb8777cf48ad7deaa9440858bacf4bbb Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Sun, 6 Oct 2024 21:01:32 +0900
Subject: [PATCH 15/28] =?UTF-8?q?refactor:=20Mocking=20=EB=B0=A9=EC=8B=9D?=
 =?UTF-8?q?=20=EB=B3=80=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/spaces/spaces.controller.spec.ts      | 112 +++++++++---------
 1 file changed, 56 insertions(+), 56 deletions(-)

diff --git a/nestjs-BE/server/src/spaces/spaces.controller.spec.ts b/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
index 5dcb5eec..ca374aa1 100644
--- a/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
+++ b/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
@@ -71,9 +71,9 @@ describe('SpacesController', () => {
     } as CreateSpaceRequestDto;
     const spaceMock = { uuid: 'space uuid' } as Space;
 
-    jest.spyOn(usersService, 'verifyUserProfile').mockResolvedValue(true);
-    jest.spyOn(uploadService, 'uploadFile').mockResolvedValue(iconUrlMock);
-    jest.spyOn(spacesService, 'createSpace').mockResolvedValue(spaceMock);
+    (usersService.verifyUserProfile as jest.Mock).mockResolvedValue(true);
+    (uploadService.uploadFile as jest.Mock).mockResolvedValue(iconUrlMock);
+    (spacesService.createSpace as jest.Mock).mockResolvedValue(spaceMock);
 
     const response = controller.create(iconMock, bodyMock, requestMock);
 
@@ -98,9 +98,9 @@ describe('SpacesController', () => {
     } as CreateSpaceRequestDto;
     const requestMock = { user: { uuid: 'user uuid' } } as RequestWithUser;
 
-    jest
-      .spyOn(usersService, 'verifyUserProfile')
-      .mockRejectedValue(new NotFoundException());
+    (usersService.verifyUserProfile as jest.Mock).mockRejectedValue(
+      new NotFoundException(),
+    );
 
     const response = controller.create(iconMock, bodyMock, requestMock);
 
@@ -121,9 +121,9 @@ describe('SpacesController', () => {
       profileUuid: profileMock.uuid,
     } as CreateSpaceRequestDto;
 
-    jest
-      .spyOn(usersService, 'verifyUserProfile')
-      .mockRejectedValue(new ForbiddenException());
+    (usersService.verifyUserProfile as jest.Mock).mockRejectedValue(
+      new ForbiddenException(),
+    );
 
     const response = controller.create(iconMock, bodyMock, requestMock);
 
@@ -144,8 +144,8 @@ describe('SpacesController', () => {
     } as CreateSpaceRequestDto;
     const spaceMock = { uuid: 'space uuid' } as Space;
 
-    jest.spyOn(usersService, 'verifyUserProfile').mockResolvedValue(true);
-    jest.spyOn(spacesService, 'createSpace').mockResolvedValue(spaceMock);
+    (usersService.verifyUserProfile as jest.Mock).mockResolvedValue(true);
+    (spacesService.createSpace as jest.Mock).mockResolvedValue(spaceMock);
 
     const response = controller.create(
       null as unknown as Express.Multer.File,
@@ -178,11 +178,11 @@ describe('SpacesController', () => {
       profileUuid: profileMock.uuid,
     };
 
-    jest.spyOn(usersService, 'verifyUserProfile').mockResolvedValue(true);
-    jest.spyOn(spacesService, 'findSpace').mockResolvedValue(spaceMock);
-    jest
-      .spyOn(profileSpaceService, 'findProfileSpaceByBothUuid')
-      .mockResolvedValue(profileSpaceMock);
+    (usersService.verifyUserProfile as jest.Mock).mockResolvedValue(true);
+    (spacesService.findSpace as jest.Mock).mockResolvedValue(spaceMock);
+    (
+      profileSpaceService.findProfileSpaceByBothUuid as jest.Mock
+    ).mockResolvedValue(profileSpaceMock);
 
     const response = controller.findOne(
       spaceMock.uuid,
@@ -215,9 +215,9 @@ describe('SpacesController', () => {
       userUuid: 'wrong user uuid',
     } as Profile;
 
-    jest
-      .spyOn(usersService, 'verifyUserProfile')
-      .mockRejectedValue(new ForbiddenException());
+    (usersService.verifyUserProfile as jest.Mock).mockRejectedValue(
+      new ForbiddenException(),
+    );
 
     const response = controller.findOne(
       spaceMock.uuid,
@@ -237,11 +237,11 @@ describe('SpacesController', () => {
       userUuid: requestMock.user.uuid,
     } as Profile;
 
-    jest.spyOn(usersService, 'verifyUserProfile').mockResolvedValue(true);
-    jest.spyOn(spacesService, 'findSpace').mockResolvedValue(spaceMock);
-    jest
-      .spyOn(profileSpaceService, 'findProfileSpaceByBothUuid')
-      .mockResolvedValue(null);
+    (usersService.verifyUserProfile as jest.Mock).mockResolvedValue(true);
+    (spacesService.findSpace as jest.Mock).mockResolvedValue(spaceMock);
+    (
+      profileSpaceService.findProfileSpaceByBothUuid as jest.Mock
+    ).mockResolvedValue(null);
 
     const response = controller.findOne(
       spaceMock.uuid,
@@ -260,8 +260,8 @@ describe('SpacesController', () => {
       userUuid: requestMock.user.uuid,
     } as Profile;
 
-    jest.spyOn(usersService, 'verifyUserProfile').mockResolvedValue(true);
-    jest.spyOn(spacesService, 'findSpace').mockResolvedValue(null);
+    (usersService.verifyUserProfile as jest.Mock).mockResolvedValue(true);
+    (spacesService.findSpace as jest.Mock).mockResolvedValue(null);
 
     const response = controller.findOne(
       spaceMock.uuid,
@@ -280,9 +280,9 @@ describe('SpacesController', () => {
       userUuid: requestMock.user.uuid,
     } as Profile;
 
-    jest
-      .spyOn(usersService, 'verifyUserProfile')
-      .mockRejectedValue(new NotFoundException());
+    (usersService.verifyUserProfile as jest.Mock).mockRejectedValue(
+      new NotFoundException(),
+    );
 
     const response = controller.findOne(
       spaceMock.uuid,
@@ -308,12 +308,12 @@ describe('SpacesController', () => {
       profileUuid: profileMock.uuid,
     };
 
-    jest.spyOn(usersService, 'verifyUserProfile').mockResolvedValue(true);
-    jest
-      .spyOn(profileSpaceService, 'findProfileSpaceByBothUuid')
-      .mockResolvedValue(profileSpaceMock);
-    jest.spyOn(uploadService, 'uploadFile').mockResolvedValue(iconUrlMock);
-    jest.spyOn(spacesService, 'updateSpace').mockResolvedValue(spaceMock);
+    (usersService.verifyUserProfile as jest.Mock).mockResolvedValue(true);
+    (
+      profileSpaceService.findProfileSpaceByBothUuid as jest.Mock
+    ).mockResolvedValue(profileSpaceMock);
+    (uploadService.uploadFile as jest.Mock).mockResolvedValue(iconUrlMock);
+    (spacesService.updateSpace as jest.Mock).mockResolvedValue(spaceMock);
 
     const response = controller.update(
       iconMock,
@@ -348,11 +348,11 @@ describe('SpacesController', () => {
       profileUuid: profileMock.uuid,
     };
 
-    jest.spyOn(usersService, 'verifyUserProfile').mockResolvedValue(true);
-    jest
-      .spyOn(profileSpaceService, 'findProfileSpaceByBothUuid')
-      .mockResolvedValue(profileSpaceMock);
-    jest.spyOn(spacesService, 'updateSpace').mockResolvedValue(spaceMock);
+    (usersService.verifyUserProfile as jest.Mock).mockResolvedValue(true);
+    (
+      profileSpaceService.findProfileSpaceByBothUuid as jest.Mock
+    ).mockResolvedValue(profileSpaceMock);
+    (spacesService.updateSpace as jest.Mock).mockResolvedValue(spaceMock);
 
     const response = controller.update(
       null as unknown as Express.Multer.File,
@@ -388,12 +388,12 @@ describe('SpacesController', () => {
       profileUuid: profileMock.uuid,
     };
 
-    jest.spyOn(usersService, 'verifyUserProfile').mockResolvedValue(true);
-    jest
-      .spyOn(profileSpaceService, 'findProfileSpaceByBothUuid')
-      .mockResolvedValue(profileSpaceMock);
-    jest.spyOn(spacesService, 'updateSpace').mockResolvedValue(spaceMock);
-    jest.spyOn(uploadService, 'uploadFile').mockResolvedValue(iconUrlMock);
+    (usersService.verifyUserProfile as jest.Mock).mockResolvedValue(true);
+    (
+      profileSpaceService.findProfileSpaceByBothUuid as jest.Mock
+    ).mockResolvedValue(profileSpaceMock);
+    (spacesService.updateSpace as jest.Mock).mockResolvedValue(spaceMock);
+    (uploadService.uploadFile as jest.Mock).mockResolvedValue(iconUrlMock);
 
     const response = controller.update(
       iconMock,
@@ -424,9 +424,9 @@ describe('SpacesController', () => {
     } as Profile;
     const bodyMock = { name: 'new space name' } as UpdateSpaceRequestDto;
 
-    jest
-      .spyOn(usersService, 'verifyUserProfile')
-      .mockRejectedValue(new ForbiddenException());
+    (usersService.verifyUserProfile as jest.Mock).mockRejectedValue(
+      new ForbiddenException(),
+    );
 
     const response = controller.update(
       iconMock,
@@ -451,10 +451,10 @@ describe('SpacesController', () => {
     } as Profile;
     const bodyMock = { name: 'new space name' } as UpdateSpaceRequestDto;
 
-    jest.spyOn(usersService, 'verifyUserProfile').mockResolvedValue(true);
-    jest
-      .spyOn(profileSpaceService, 'findProfileSpaceByBothUuid')
-      .mockResolvedValue(null);
+    (usersService.verifyUserProfile as jest.Mock).mockResolvedValue(true);
+    (
+      profileSpaceService.findProfileSpaceByBothUuid as jest.Mock
+    ).mockResolvedValue(null);
 
     const response = controller.update(
       iconMock,
@@ -479,9 +479,9 @@ describe('SpacesController', () => {
     } as Profile;
     const bodyMock = { name: 'new space name' } as UpdateSpaceRequestDto;
 
-    jest
-      .spyOn(usersService, 'verifyUserProfile')
-      .mockRejectedValue(new NotFoundException());
+    (usersService.verifyUserProfile as jest.Mock).mockRejectedValue(
+      new NotFoundException(),
+    );
 
     const response = controller.update(
       iconMock,

From b3f296dcf4ac97bc5ee93e9bb98228d3f26a25b6 Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Sun, 6 Oct 2024 21:33:35 +0900
Subject: [PATCH 16/28] =?UTF-8?q?feat:=20joinSpace=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../server/src/spaces/dto/join-space.dto.ts   | 12 +++++
 .../src/spaces/spaces.controller.spec.ts      | 21 +++++++++
 .../server/src/spaces/spaces.controller.ts    | 47 +++++++++++++++++++
 .../server/src/spaces/spaces.service.spec.ts  |  6 ++-
 nestjs-BE/server/src/spaces/spaces.service.ts |  3 +-
 5 files changed, 87 insertions(+), 2 deletions(-)
 create mode 100644 nestjs-BE/server/src/spaces/dto/join-space.dto.ts

diff --git a/nestjs-BE/server/src/spaces/dto/join-space.dto.ts b/nestjs-BE/server/src/spaces/dto/join-space.dto.ts
new file mode 100644
index 00000000..462a053e
--- /dev/null
+++ b/nestjs-BE/server/src/spaces/dto/join-space.dto.ts
@@ -0,0 +1,12 @@
+import { ApiProperty } from '@nestjs/swagger';
+import { Expose } from 'class-transformer';
+import { IsNotEmpty, IsString } from 'class-validator';
+import { v4 as uuid } from 'uuid';
+
+export class JoinSpaceRequestDto {
+  @IsString()
+  @IsNotEmpty()
+  @Expose({ name: 'profile_uuid' })
+  @ApiProperty({ example: uuid(), description: 'Profile uuid' })
+  profileUuid: string;
+}
diff --git a/nestjs-BE/server/src/spaces/spaces.controller.spec.ts b/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
index ca374aa1..a6501ded 100644
--- a/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
+++ b/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
@@ -35,6 +35,7 @@ describe('SpacesController', () => {
             createSpace: jest.fn(),
             findSpace: jest.fn(),
             updateSpace: jest.fn(),
+            joinSpace: jest.fn(),
           },
         },
         { provide: UploadService, useValue: { uploadFile: jest.fn() } },
@@ -495,4 +496,24 @@ describe('SpacesController', () => {
     expect(uploadService.uploadFile).not.toHaveBeenCalled();
     expect(spacesService.updateSpace).not.toHaveBeenCalled();
   });
+
+  it('joinSpace', async () => {
+    const spaceMock = { uuid: 'space uuid' };
+    const bodyMock = { profileUuid: 'profile uuid' };
+    const requestMock = { user: { uuid: 'user uuid' } } as RequestWithUser;
+
+    (spacesService.joinSpace as jest.Mock).mockResolvedValue(spaceMock);
+
+    const response = controller.joinSpace(
+      spaceMock.uuid,
+      bodyMock,
+      requestMock,
+    );
+
+    await expect(response).resolves.toEqual({
+      statusCode: HttpStatus.CREATED,
+      message: 'Created',
+      data: spaceMock,
+    });
+  });
 });
diff --git a/nestjs-BE/server/src/spaces/spaces.controller.ts b/nestjs-BE/server/src/spaces/spaces.controller.ts
index b2ad19b8..e23800b9 100644
--- a/nestjs-BE/server/src/spaces/spaces.controller.ts
+++ b/nestjs-BE/server/src/spaces/spaces.controller.ts
@@ -26,6 +26,7 @@ import { ProfileSpaceService } from '../profile-space/profile-space.service';
 import { RequestWithUser } from '../utils/interface';
 import { ConfigService } from '@nestjs/config';
 import { UsersService } from '../users/users.service';
+import { JoinSpaceRequestDto } from './dto/join-space.dto';
 
 @Controller('spaces')
 @ApiTags('spaces')
@@ -180,4 +181,50 @@ export class SpacesController {
     if (!space) throw new NotFoundException();
     return { statusCode: HttpStatus.OK, message: 'OK', data: space };
   }
+
+  @Post(':space_uuid/join')
+  @ApiOperation({ summary: 'Join space' })
+  @ApiResponse({
+    status: HttpStatus.CREATED,
+    description: 'Join data has been successfully created.',
+  })
+  @ApiResponse({
+    status: HttpStatus.BAD_REQUEST,
+    description: 'Profile uuid needed.',
+  })
+  @ApiResponse({
+    status: HttpStatus.UNAUTHORIZED,
+    description: 'User not logged in.',
+  })
+  @ApiResponse({
+    status: HttpStatus.FORBIDDEN,
+    description: 'Profile user not own.',
+  })
+  @ApiResponse({
+    status: HttpStatus.NOT_FOUND,
+    description: 'Profile not found.',
+  })
+  @ApiResponse({
+    status: HttpStatus.CONFLICT,
+    description: 'Conflict. You have already joined the space.',
+  })
+  async joinSpace(
+    @Param('space_uuid') spaceUuid: string,
+    @Body(
+      new ValidationPipe({
+        transform: true,
+        whitelist: true,
+        disableErrorMessages: true,
+      }),
+    )
+    joinSpaceDto: JoinSpaceRequestDto,
+    @Req() req: RequestWithUser,
+  ) {
+    const space = await this.spacesService.joinSpace(
+      req.user.uuid,
+      joinSpaceDto.profileUuid,
+      spaceUuid,
+    );
+    return { statusCode: HttpStatus.CREATED, message: 'Created', data: space };
+  }
 }
diff --git a/nestjs-BE/server/src/spaces/spaces.service.spec.ts b/nestjs-BE/server/src/spaces/spaces.service.spec.ts
index 42f43896..16355fc3 100644
--- a/nestjs-BE/server/src/spaces/spaces.service.spec.ts
+++ b/nestjs-BE/server/src/spaces/spaces.service.spec.ts
@@ -9,6 +9,7 @@ import { PrismaService } from '../prisma/prisma.service';
 import { PrismaClientKnownRequestError } from '@prisma/client/runtime/library';
 import { ProfileSpaceService } from '../profile-space/profile-space.service';
 import { UsersService } from '../users/users.service';
+import { Space } from '@prisma/client';
 
 describe('SpacesService', () => {
   let spacesService: SpacesService;
@@ -88,10 +89,13 @@ describe('SpacesService', () => {
     const userUuid = 'user uuid';
     const profileUuid = 'profile uuid';
     const spaceUuid = 'space uuid';
+    const space = { uuid: spaceUuid } as Space;
+
+    jest.spyOn(spacesService, 'findSpace').mockResolvedValue(space);
 
     const res = spacesService.joinSpace(userUuid, profileUuid, spaceUuid);
 
-    await expect(res).resolves.toBeUndefined();
+    await expect(res).resolves.toEqual(space);
   });
 
   it('joinSpace profile not found', async () => {
diff --git a/nestjs-BE/server/src/spaces/spaces.service.ts b/nestjs-BE/server/src/spaces/spaces.service.ts
index 47bd1cf6..26152155 100644
--- a/nestjs-BE/server/src/spaces/spaces.service.ts
+++ b/nestjs-BE/server/src/spaces/spaces.service.ts
@@ -64,7 +64,7 @@ export class SpacesService {
     userUuid: string,
     profileUuid: string,
     spaceUuid: string,
-  ): Promise<void> {
+  ): Promise<Space> {
     await this.usersService.verifyUserProfile(userUuid, profileUuid);
     try {
       await this.profileSpaceService.createProfileSpace(profileUuid, spaceUuid);
@@ -82,6 +82,7 @@ export class SpacesService {
         throw err;
       }
     }
+    return this.findSpace(spaceUuid);
   }
 
   async leaveSpace(

From 268392bfa3fb1bc531014b928fb0e23ead894686 Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Sun, 6 Oct 2024 21:41:40 +0900
Subject: [PATCH 17/28] =?UTF-8?q?feat:=20leaveSpace=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/spaces/spaces.controller.spec.ts      | 20 +++++++++++
 .../server/src/spaces/spaces.controller.ts    | 34 +++++++++++++++++++
 2 files changed, 54 insertions(+)

diff --git a/nestjs-BE/server/src/spaces/spaces.controller.spec.ts b/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
index a6501ded..74a5d510 100644
--- a/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
+++ b/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
@@ -36,6 +36,7 @@ describe('SpacesController', () => {
             findSpace: jest.fn(),
             updateSpace: jest.fn(),
             joinSpace: jest.fn(),
+            leaveSpace: jest.fn(),
           },
         },
         { provide: UploadService, useValue: { uploadFile: jest.fn() } },
@@ -516,4 +517,23 @@ describe('SpacesController', () => {
       data: spaceMock,
     });
   });
+
+  it('leaveSpace', async () => {
+    const spaceMock = { uuid: 'space uuid' };
+    const profileMock = { uuid: 'profile uuid' };
+    const requestMock = { user: { uuid: 'user uuid' } } as RequestWithUser;
+
+    (spacesService.leaveSpace as jest.Mock).mockResolvedValue(undefined);
+
+    const response = controller.leaveSpace(
+      spaceMock.uuid,
+      profileMock.uuid,
+      requestMock,
+    );
+
+    await expect(response).resolves.toEqual({
+      statusCode: HttpStatus.NO_CONTENT,
+      message: 'No Content',
+    });
+  });
 });
diff --git a/nestjs-BE/server/src/spaces/spaces.controller.ts b/nestjs-BE/server/src/spaces/spaces.controller.ts
index e23800b9..30326d0a 100644
--- a/nestjs-BE/server/src/spaces/spaces.controller.ts
+++ b/nestjs-BE/server/src/spaces/spaces.controller.ts
@@ -15,6 +15,8 @@ import {
   ForbiddenException,
   Query,
   BadRequestException,
+  Delete,
+  HttpCode,
 } from '@nestjs/common';
 import { FileInterceptor } from '@nestjs/platform-express';
 import { SpacesService } from './spaces.service';
@@ -227,4 +229,36 @@ export class SpacesController {
     );
     return { statusCode: HttpStatus.CREATED, message: 'Created', data: space };
   }
+
+  @Delete(':space_uuid/profiles/:profile_uuid')
+  @HttpCode(HttpStatus.NO_CONTENT)
+  @ApiOperation({ summary: 'Leave space' })
+  @ApiResponse({
+    status: HttpStatus.NO_CONTENT,
+    description: 'Successfully left the space.',
+  })
+  @ApiResponse({
+    status: HttpStatus.BAD_REQUEST,
+    description: 'Profile uuid needed.',
+  })
+  @ApiResponse({
+    status: HttpStatus.UNAUTHORIZED,
+    description: 'User not logged in.',
+  })
+  @ApiResponse({
+    status: HttpStatus.FORBIDDEN,
+    description: 'Profile user not own.',
+  })
+  @ApiResponse({
+    status: HttpStatus.NOT_FOUND,
+    description: 'Profile not found. Profile not joined space.',
+  })
+  async leaveSpace(
+    @Param('space_uuid') spaceUuid: string,
+    @Param('profile_uuid') profileUuid: string,
+    @Req() req: RequestWithUser,
+  ) {
+    await this.spacesService.leaveSpace(req.user.uuid, profileUuid, spaceUuid);
+    return { statusCode: HttpStatus.NO_CONTENT, message: 'No Content' };
+  }
 }

From baf605b8c095ceff47c63f14d19f12f6dbab28fe Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Sun, 6 Oct 2024 22:01:53 +0900
Subject: [PATCH 18/28] =?UTF-8?q?feat:=20findProfilesInSpace=20=EC=B6=94?=
 =?UTF-8?q?=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../src/spaces/spaces.controller.spec.ts      | 39 +++++++++++++++++++
 .../server/src/spaces/spaces.controller.ts    | 37 ++++++++++++++++++
 2 files changed, 76 insertions(+)

diff --git a/nestjs-BE/server/src/spaces/spaces.controller.spec.ts b/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
index 74a5d510..b7745766 100644
--- a/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
+++ b/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
@@ -37,6 +37,7 @@ describe('SpacesController', () => {
             updateSpace: jest.fn(),
             joinSpace: jest.fn(),
             leaveSpace: jest.fn(),
+            findProfilesInSpace: jest.fn(),
           },
         },
         { provide: UploadService, useValue: { uploadFile: jest.fn() } },
@@ -536,4 +537,42 @@ describe('SpacesController', () => {
       message: 'No Content',
     });
   });
+
+  it('findProfilesInSpace', async () => {
+    const spaceMock = { uuid: 'space uuid' };
+    const profileMock = { uuid: 'profile uuid' };
+    const requestMock = { user: { uuid: 'user uuid' } } as RequestWithUser;
+    const profilesMock = [];
+
+    (spacesService.findProfilesInSpace as jest.Mock).mockResolvedValue(
+      profilesMock,
+    );
+
+    const response = controller.findProfilesInSpace(
+      spaceMock.uuid,
+      profileMock.uuid,
+      requestMock,
+    );
+
+    await expect(response).resolves.toEqual({
+      statusCode: HttpStatus.OK,
+      message: 'OK',
+      data: profilesMock,
+    });
+  });
+
+  it('findProfilesInSpace space uuid needed', async () => {
+    const spaceMock = { uuid: 'space uuid' };
+    const requestMock = { user: { uuid: 'user uuid' } } as RequestWithUser;
+
+    (spacesService.findProfilesInSpace as jest.Mock).mockResolvedValue([]);
+
+    const response = controller.findProfilesInSpace(
+      spaceMock.uuid,
+      undefined,
+      requestMock,
+    );
+
+    await expect(response).rejects.toThrow(BadRequestException);
+  });
 });
diff --git a/nestjs-BE/server/src/spaces/spaces.controller.ts b/nestjs-BE/server/src/spaces/spaces.controller.ts
index 30326d0a..cf2a7170 100644
--- a/nestjs-BE/server/src/spaces/spaces.controller.ts
+++ b/nestjs-BE/server/src/spaces/spaces.controller.ts
@@ -261,4 +261,41 @@ export class SpacesController {
     await this.spacesService.leaveSpace(req.user.uuid, profileUuid, spaceUuid);
     return { statusCode: HttpStatus.NO_CONTENT, message: 'No Content' };
   }
+
+  @Get(':space_uuid/profiles')
+  @Header('Cache-Control', 'no-store')
+  @ApiOperation({ summary: 'Get profiles joined space.' })
+  @ApiResponse({
+    status: HttpStatus.OK,
+    description: 'Successfully get profiles.',
+  })
+  @ApiResponse({
+    status: HttpStatus.BAD_REQUEST,
+    description: 'Profile uuid needed.',
+  })
+  @ApiResponse({
+    status: HttpStatus.UNAUTHORIZED,
+    description: 'User not logged in.',
+  })
+  @ApiResponse({
+    status: HttpStatus.FORBIDDEN,
+    description: 'Profile user not own.',
+  })
+  @ApiResponse({
+    status: HttpStatus.NOT_FOUND,
+    description: 'Profile not found. Profile not joined space.',
+  })
+  async findProfilesInSpace(
+    @Param('space_uuid') spaceUuid: string,
+    @Query('profile_uuid') profileUuid: string,
+    @Req() req: RequestWithUser,
+  ) {
+    if (!profileUuid) throw new BadRequestException();
+    const profiles = await this.spacesService.findProfilesInSpace(
+      req.user.uuid,
+      profileUuid,
+      spaceUuid,
+    );
+    return { statusCode: HttpStatus.OK, message: 'OK', data: profiles };
+  }
 }

From 418a2c07fdc657786c395adf04f382244891c79f Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Sun, 6 Oct 2024 22:27:06 +0900
Subject: [PATCH 19/28] =?UTF-8?q?feat:=20=EB=AA=A8=EB=93=88=EC=97=90=20?=
 =?UTF-8?q?=EB=A7=9E=EC=A7=80=20=EC=95=8A=EC=9D=80=20controller=20?=
 =?UTF-8?q?=EC=A0=9C=EA=B1=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../dto/create-profile-space.dto.ts           |  14 --
 .../dto/update-profile-space.dto.ts           |   6 -
 .../profile-space/profile-space.controller.ts | 126 ------------------
 .../src/profile-space/profile-space.module.ts |   7 +-
 .../profile-space/profile-space.service.ts    |  38 ------
 nestjs-BE/server/src/spaces/spaces.module.ts  |   4 +-
 6 files changed, 4 insertions(+), 191 deletions(-)
 delete mode 100644 nestjs-BE/server/src/profile-space/dto/create-profile-space.dto.ts
 delete mode 100644 nestjs-BE/server/src/profile-space/dto/update-profile-space.dto.ts
 delete mode 100644 nestjs-BE/server/src/profile-space/profile-space.controller.ts

diff --git a/nestjs-BE/server/src/profile-space/dto/create-profile-space.dto.ts b/nestjs-BE/server/src/profile-space/dto/create-profile-space.dto.ts
deleted file mode 100644
index fdd16f5c..00000000
--- a/nestjs-BE/server/src/profile-space/dto/create-profile-space.dto.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-import { IsNotEmpty, IsString } from 'class-validator';
-import { ApiProperty } from '@nestjs/swagger';
-
-export class CreateProfileSpaceDto {
-  @ApiProperty({
-    example: 'space uuid',
-    description: 'Space UUID',
-  })
-  @IsNotEmpty()
-  @IsString()
-  space_uuid: string;
-
-  profile_uuid: string;
-}
diff --git a/nestjs-BE/server/src/profile-space/dto/update-profile-space.dto.ts b/nestjs-BE/server/src/profile-space/dto/update-profile-space.dto.ts
deleted file mode 100644
index 9bef8027..00000000
--- a/nestjs-BE/server/src/profile-space/dto/update-profile-space.dto.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { PartialType } from '@nestjs/swagger';
-import { CreateProfileSpaceDto } from './create-profile-space.dto';
-
-export class UpdateProfileSpaceDto extends PartialType(CreateProfileSpaceDto) {
-  uuid?: string;
-}
diff --git a/nestjs-BE/server/src/profile-space/profile-space.controller.ts b/nestjs-BE/server/src/profile-space/profile-space.controller.ts
deleted file mode 100644
index 30573c4d..00000000
--- a/nestjs-BE/server/src/profile-space/profile-space.controller.ts
+++ /dev/null
@@ -1,126 +0,0 @@
-import {
-  Controller,
-  Get,
-  Post,
-  Body,
-  Delete,
-  Param,
-  Request as Req,
-  NotFoundException,
-  HttpException,
-  HttpStatus,
-  ConflictException,
-} from '@nestjs/common';
-import { ProfileSpaceService } from './profile-space.service';
-import { CreateProfileSpaceDto } from './dto/create-profile-space.dto';
-import { RequestWithUser } from '../utils/interface';
-import { SpacesService } from '../spaces/spaces.service';
-import { ApiTags, ApiResponse, ApiOperation } from '@nestjs/swagger';
-import { ProfilesService } from '../profiles/profiles.service';
-
-@Controller('profileSpace')
-@ApiTags('profileSpace')
-export class ProfileSpaceController {
-  constructor(
-    private readonly profileSpaceService: ProfileSpaceService,
-    private readonly spacesService: SpacesService,
-    private readonly profilesService: ProfilesService,
-  ) {}
-
-  @Post('join')
-  @ApiOperation({ summary: 'Join space' })
-  @ApiResponse({
-    status: 201,
-    description: 'Join data has been successfully created.',
-  })
-  @ApiResponse({
-    status: 409,
-    description: 'Conflict. You have already joined the space.',
-  })
-  async create(
-    @Body() createProfileSpaceDto: CreateProfileSpaceDto,
-    @Req() req: RequestWithUser,
-  ) {
-    const profile = await this.profilesService.findProfile(req.user.uuid);
-    if (!profile) throw new NotFoundException();
-    const profileSpace = await this.profileSpaceService.joinSpace(
-      profile.uuid,
-      createProfileSpaceDto.space_uuid,
-    );
-    if (!profileSpace) {
-      throw new HttpException('Data already exists.', HttpStatus.CONFLICT);
-    }
-    return { statusCode: 201, message: 'Created', data: profileSpace };
-  }
-
-  @Delete('leave/:space_uuid')
-  @ApiResponse({
-    status: 204,
-    description: 'Successfully left the space.',
-  })
-  @ApiResponse({
-    status: 404,
-    description: 'Space not found.',
-  })
-  async delete(
-    @Param('space_uuid') spaceUuid: string,
-    @Req() req: RequestWithUser,
-  ) {
-    const profile = await this.profilesService.findProfile(req.user.uuid);
-    if (!profile) throw new NotFoundException();
-    const space = await this.spacesService.findSpace(spaceUuid);
-    if (!space) throw new NotFoundException();
-    const profileSpace = await this.profileSpaceService.leaveSpace(
-      profile.uuid,
-      spaceUuid,
-    );
-    if (!profileSpace) throw new ConflictException();
-    const isSpaceEmpty = await this.profileSpaceService.isSpaceEmpty(spaceUuid);
-    if (isSpaceEmpty) {
-      await this.spacesService.deleteSpace(spaceUuid);
-    }
-    return { statusCode: 204, message: 'No Content' };
-  }
-
-  @Get('spaces')
-  @ApiOperation({ summary: "Get user's spaces" })
-  @ApiResponse({
-    status: 200,
-    description: 'Returns a list of spaces.',
-  })
-  async getSpaces(@Req() req: RequestWithUser) {
-    const profile = await this.profilesService.findProfile(req.user.uuid);
-    if (!profile) throw new NotFoundException();
-    const profileSpaces =
-      await this.profileSpaceService.findProfileSpacesByProfileUuid(
-        profile.uuid,
-      );
-    const spaceUuids = profileSpaces.map(
-      (profileSpace) => profileSpace.spaceUuid,
-    );
-    const spaces = await this.spacesService.findSpaces(spaceUuids);
-    return { statusCode: 200, message: 'Success', data: spaces };
-  }
-
-  @Get('users/:space_uuid')
-  @ApiOperation({ summary: 'Get users in the space' })
-  @ApiResponse({
-    status: 200,
-    description: 'Returns a list of users.',
-  })
-  @ApiResponse({
-    status: 404,
-    description: 'Space not found.',
-  })
-  async getProfiles(@Param('space_uuid') spaceUuid: string) {
-    const space = await this.spacesService.findSpace(spaceUuid);
-    if (!space) throw new NotFoundException();
-    const profileSpaces =
-      await this.profileSpaceService.findProfileSpacesBySpaceUuid(space.uuid);
-    const profileUuids = profileSpaces.map(
-      (profileSpace) => profileSpace.profileUuid,
-    );
-    const profiles = await this.profilesService.findProfiles(profileUuids);
-    return { statusCode: 200, message: 'Success', data: profiles };
-  }
-}
diff --git a/nestjs-BE/server/src/profile-space/profile-space.module.ts b/nestjs-BE/server/src/profile-space/profile-space.module.ts
index 9e662309..90e8a178 100644
--- a/nestjs-BE/server/src/profile-space/profile-space.module.ts
+++ b/nestjs-BE/server/src/profile-space/profile-space.module.ts
@@ -1,12 +1,9 @@
-import { Module, forwardRef } from '@nestjs/common';
+import { Module } from '@nestjs/common';
 import { ProfileSpaceService } from './profile-space.service';
-import { ProfileSpaceController } from './profile-space.controller';
 import { ProfilesModule } from '../profiles/profiles.module';
-import { SpacesModule } from '../spaces/spaces.module';
 
 @Module({
-  imports: [ProfilesModule, forwardRef(() => SpacesModule)],
-  controllers: [ProfileSpaceController],
+  imports: [ProfilesModule],
   providers: [ProfileSpaceService],
   exports: [ProfileSpaceService],
 })
diff --git a/nestjs-BE/server/src/profile-space/profile-space.service.ts b/nestjs-BE/server/src/profile-space/profile-space.service.ts
index a1e4769e..383d8988 100644
--- a/nestjs-BE/server/src/profile-space/profile-space.service.ts
+++ b/nestjs-BE/server/src/profile-space/profile-space.service.ts
@@ -24,22 +24,6 @@ export class ProfileSpaceService {
     });
   }
 
-  async findProfileSpacesByProfileUuid(
-    profileUuid: string,
-  ): Promise<ProfileSpace[]> {
-    return this.prisma.profileSpace.findMany({
-      where: { profileUuid: profileUuid },
-    });
-  }
-
-  async findProfileSpacesBySpaceUuid(
-    spaceUuid: string,
-  ): Promise<ProfileSpace[]> {
-    return this.prisma.profileSpace.findMany({
-      where: { spaceUuid: spaceUuid },
-    });
-  }
-
   async findProfileSpaceByBothUuid(
     profileUuid: string,
     spaceUuid: string,
@@ -66,28 +50,6 @@ export class ProfileSpaceService {
     }
   }
 
-  async leaveSpace(
-    profileUuid: string,
-    spaceUuid: string,
-  ): Promise<ProfileSpace | null> {
-    try {
-      return await this.prisma.profileSpace.delete({
-        where: {
-          spaceUuid_profileUuid: {
-            spaceUuid: spaceUuid,
-            profileUuid: profileUuid,
-          },
-        },
-      });
-    } catch (err) {
-      if (err instanceof Prisma.PrismaClientKnownRequestError) {
-        return null;
-      } else {
-        throw err;
-      }
-    }
-  }
-
   async isSpaceEmpty(spaceUuid: string) {
     const first = await this.prisma.profileSpace.findFirst({
       where: {
diff --git a/nestjs-BE/server/src/spaces/spaces.module.ts b/nestjs-BE/server/src/spaces/spaces.module.ts
index 3bd19f1d..8c00d20f 100644
--- a/nestjs-BE/server/src/spaces/spaces.module.ts
+++ b/nestjs-BE/server/src/spaces/spaces.module.ts
@@ -1,4 +1,4 @@
-import { forwardRef, Module } from '@nestjs/common';
+import { Module } from '@nestjs/common';
 import { SpacesService } from './spaces.service';
 import { SpacesController } from './spaces.controller';
 import { UploadModule } from '../upload/upload.module';
@@ -6,7 +6,7 @@ import { ProfileSpaceModule } from '../profile-space/profile-space.module';
 import { UsersModule } from '../users/users.module';
 
 @Module({
-  imports: [forwardRef(() => ProfileSpaceModule), UploadModule, UsersModule],
+  imports: [ProfileSpaceModule, UploadModule, UsersModule],
   controllers: [SpacesController],
   providers: [SpacesService],
   exports: [SpacesService],

From 665dc6be40d37fec70735cd52df7ce1a0a7e615a Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Mon, 7 Oct 2024 17:27:49 +0900
Subject: [PATCH 20/28] =?UTF-8?q?fix:=20uuid=20=ED=95=A8=EC=88=98=20?=
 =?UTF-8?q?=EB=B3=80=EA=B2=BD=EC=97=90=20=EB=94=B0=EB=9D=BC=EC=84=9C=20?=
 =?UTF-8?q?=ED=8C=A8=ED=84=B4=20=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 nestjs-BE/server/test/spaces.e2e-spec.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/nestjs-BE/server/test/spaces.e2e-spec.ts b/nestjs-BE/server/test/spaces.e2e-spec.ts
index 322b28b6..af4bcff5 100644
--- a/nestjs-BE/server/test/spaces.e2e-spec.ts
+++ b/nestjs-BE/server/test/spaces.e2e-spec.ts
@@ -302,7 +302,7 @@ describe('SpacesController (e2e)', () => {
       'S3_BUCKET_NAME',
     )}\\.s3\\.${configService.get<string>(
       'AWS_REGION',
-    )}\\.amazonaws\\.com\\/[0-9a-f]{32}-`;
+    )}\\.amazonaws\\.com\\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}-`;
     const imageRegExp = new RegExp(imageUrlPattern);
 
     return request(app.getHttpServer())
@@ -329,7 +329,7 @@ describe('SpacesController (e2e)', () => {
       'S3_BUCKET_NAME',
     )}\\.s3\\.${configService.get<string>(
       'AWS_REGION',
-    )}\\.amazonaws\\.com\\/[0-9a-f]{32}-`;
+    )}\\.amazonaws\\.com\\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}-`;
     const imageRegExp = new RegExp(imageUrlPattern);
     await prisma.profileSpace.create({
       data: { spaceUuid: testSpace.uuid, profileUuid: testProfile.uuid },

From 9f8e241479c9c03d720024921911aac0325d744a Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Mon, 7 Oct 2024 17:46:19 +0900
Subject: [PATCH 21/28] =?UTF-8?q?test:=20=EC=8A=A4=ED=8E=98=EC=9D=B4?=
 =?UTF-8?q?=EC=8A=A4=20=EC=B0=B8=EA=B0=80=20API=20=ED=85=8C=EC=8A=A4?=
 =?UTF-8?q?=ED=8A=B8=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 nestjs-BE/server/test/spaces.e2e-spec.ts | 114 +++++++++++++++++++++++
 1 file changed, 114 insertions(+)

diff --git a/nestjs-BE/server/test/spaces.e2e-spec.ts b/nestjs-BE/server/test/spaces.e2e-spec.ts
index af4bcff5..b018fa22 100644
--- a/nestjs-BE/server/test/spaces.e2e-spec.ts
+++ b/nestjs-BE/server/test/spaces.e2e-spec.ts
@@ -470,4 +470,118 @@ describe('SpacesController (e2e)', () => {
       .expect(HttpStatus.NOT_FOUND)
       .expect({ message: 'Not Found', statusCode: HttpStatus.NOT_FOUND });
   });
+
+  it('/spaces/:space_uuid/join (POST)', async () => {
+    return request(app.getHttpServer())
+      .post(`/spaces/${testSpace.uuid}/join`)
+      .auth(testToken, { type: 'bearer' })
+      .send({ profile_uuid: testProfile.uuid })
+      .expect(HttpStatus.CREATED)
+      .expect({
+        message: 'Created',
+        statusCode: HttpStatus.CREATED,
+        data: testSpace,
+      });
+  });
+
+  it('/spaces/:space_uuid/join (POST) profile uuid needed', async () => {
+    return request(app.getHttpServer())
+      .post(`/spaces/${testSpace.uuid}/join`)
+      .auth(testToken, { type: 'bearer' })
+      .expect(HttpStatus.BAD_REQUEST)
+      .expect({
+        message: 'Bad Request',
+        statusCode: HttpStatus.BAD_REQUEST,
+      });
+  });
+
+  it('/spaces/:space_uuid/join (POST) profile uuid wrong type', async () => {
+    const number = 1;
+
+    return request(app.getHttpServer())
+      .post(`/spaces/${testSpace.uuid}/join`)
+      .auth(testToken, { type: 'bearer' })
+      .send({ profile_uuid: number })
+      .expect(HttpStatus.BAD_REQUEST)
+      .expect({
+        message: 'Bad Request',
+        statusCode: HttpStatus.BAD_REQUEST,
+      });
+  });
+
+  it('/spaces/:space_uuid/join (POST) user not logged in', async () => {
+    return request(app.getHttpServer())
+      .post(`/spaces/${testSpace.uuid}/join`)
+      .send({ profile_uuid: testProfile.uuid })
+      .expect(HttpStatus.UNAUTHORIZED)
+      .expect({
+        message: 'Unauthorized',
+        statusCode: HttpStatus.UNAUTHORIZED,
+      });
+  });
+
+  it('/spaces/:space_uuid/join (POST) profile user not own', async () => {
+    const newUser = await prisma.user.create({ data: { uuid: uuid() } });
+    const newProfile = await prisma.profile.create({
+      data: {
+        uuid: uuid(),
+        userUuid: newUser.uuid,
+        image: 'test image',
+        nickname: 'test nickname',
+      },
+    });
+
+    return request(app.getHttpServer())
+      .post(`/spaces/${testSpace.uuid}/join`)
+      .auth(testToken, { type: 'bearer' })
+      .send({ profile_uuid: newProfile.uuid })
+      .expect(HttpStatus.FORBIDDEN)
+      .expect({
+        message: 'Forbidden',
+        statusCode: HttpStatus.FORBIDDEN,
+      });
+  });
+
+  it('/spaces/:space_uuid/join (POST) space not exist', async () => {
+    return request(app.getHttpServer())
+      .post(`/spaces/${uuid()}/join`)
+      .auth(testToken, { type: 'bearer' })
+      .send({ profile_uuid: testProfile.uuid })
+      .expect(HttpStatus.FORBIDDEN)
+      .expect({
+        message: 'Forbidden',
+        statusCode: HttpStatus.FORBIDDEN,
+      });
+  });
+
+  it('/spaces/:space_uuid/join (POST) profile not found', async () => {
+    return request(app.getHttpServer())
+      .post(`/spaces/${testSpace.uuid}/join`)
+      .auth(testToken, { type: 'bearer' })
+      .send({ profile_uuid: uuid() })
+      .expect(HttpStatus.NOT_FOUND)
+      .expect({
+        message: 'Not Found',
+        statusCode: HttpStatus.NOT_FOUND,
+      });
+  });
+
+  it('/spaces/:space_uuid/join (POST) already joined space', async () => {
+    await prisma.profileSpace.create({
+      data: {
+        spaceUuid: testSpace.uuid,
+        profileUuid: testProfile.uuid,
+      },
+    });
+
+    return request(app.getHttpServer())
+      .post(`/spaces/${testSpace.uuid}/join`)
+      .auth(testToken, { type: 'bearer' })
+      .send({ profile_uuid: testProfile.uuid })
+      .expect(HttpStatus.CONFLICT)
+      .expect({
+        message: 'Conflict',
+        statusCode: HttpStatus.CONFLICT,
+      });
+  });
 });

From 9411967aa70a936c05d4d331bcf669265e02393d Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Mon, 7 Oct 2024 18:30:47 +0900
Subject: [PATCH 22/28] =?UTF-8?q?test:=20=EC=8A=A4=ED=8E=98=EC=9D=B4?=
 =?UTF-8?q?=EC=8A=A4=20=EB=82=98=EA=B0=80=EA=B8=B0=20API=20=ED=85=8C?=
 =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 nestjs-BE/server/test/spaces.e2e-spec.ts | 76 ++++++++++++++++++++++++
 1 file changed, 76 insertions(+)

diff --git a/nestjs-BE/server/test/spaces.e2e-spec.ts b/nestjs-BE/server/test/spaces.e2e-spec.ts
index b018fa22..92a49cf7 100644
--- a/nestjs-BE/server/test/spaces.e2e-spec.ts
+++ b/nestjs-BE/server/test/spaces.e2e-spec.ts
@@ -584,4 +584,80 @@ describe('SpacesController (e2e)', () => {
         statusCode: HttpStatus.CONFLICT,
       });
   });
+
+  it('/spaces/:space_uuid/profiles/:profile_uuid (DELETE)', async () => {
+    await prisma.profileSpace.create({
+      data: {
+        profileUuid: testProfile.uuid,
+        spaceUuid: testSpace.uuid,
+      },
+    });
+
+    return request(app.getHttpServer())
+      .delete(`/spaces/${testSpace.uuid}/profiles/${testProfile.uuid}`)
+      .auth(testToken, { type: 'bearer' })
+      .expect(HttpStatus.OK)
+      .expect({ message: 'OK', statusCode: HttpStatus.OK });
+  });
+
+  it('/spaces/:space_uuid/profiles/:profile_uuid (DELETE) user not logged in', async () => {
+    await prisma.profileSpace.create({
+      data: {
+        profileUuid: testProfile.uuid,
+        spaceUuid: testSpace.uuid,
+      },
+    });
+
+    return request(app.getHttpServer())
+      .delete(`/spaces/${testSpace.uuid}/profiles/${testProfile.uuid}`)
+      .expect(HttpStatus.UNAUTHORIZED)
+      .expect({ message: 'Unauthorized', statusCode: HttpStatus.UNAUTHORIZED });
+  });
+
+  it('/spaces/:space_uuid/profiles/:profile_uuid (DELETE) profile user not own', async () => {
+    const newUser = await prisma.user.create({ data: { uuid: uuid() } });
+    const newProfile = await prisma.profile.create({
+      data: {
+        uuid: uuid(),
+        userUuid: newUser.uuid,
+        image: 'test image',
+        nickname: 'test nickname',
+      },
+    });
+    await prisma.profileSpace.create({
+      data: {
+        profileUuid: testProfile.uuid,
+        spaceUuid: testSpace.uuid,
+      },
+    });
+
+    return request(app.getHttpServer())
+      .delete(`/spaces/${testSpace.uuid}/profiles/${newProfile.uuid}`)
+      .auth(testToken, { type: 'bearer' })
+      .expect(HttpStatus.FORBIDDEN)
+      .expect({ message: 'Forbidden', statusCode: HttpStatus.FORBIDDEN });
+  });
+
+  it('/spaces/:space_uuid/profiles/:profile_uuid (DELETE) profile user not own', async () => {
+    await prisma.profileSpace.create({
+      data: {
+        profileUuid: testProfile.uuid,
+        spaceUuid: testSpace.uuid,
+      },
+    });
+
+    return request(app.getHttpServer())
+      .delete(`/spaces/${testSpace.uuid}/profiles/${uuid()}`)
+      .auth(testToken, { type: 'bearer' })
+      .expect(HttpStatus.NOT_FOUND)
+      .expect({ message: 'Not Found', statusCode: HttpStatus.NOT_FOUND });
+  });
+
+  it('/spaces/:space_uuid/profiles/:profile_uuid (DELETE) profile user not own', async () => {
+    return request(app.getHttpServer())
+      .delete(`/spaces/${testSpace.uuid}/profiles/${testProfile.uuid}`)
+      .auth(testToken, { type: 'bearer' })
+      .expect(HttpStatus.NOT_FOUND)
+      .expect({ message: 'Not Found', statusCode: HttpStatus.NOT_FOUND });
+  });
 });

From d614c8cd54b202ec92bc7e34090f270f03bb0204 Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Mon, 7 Oct 2024 18:32:32 +0900
Subject: [PATCH 23/28] =?UTF-8?q?fix:=20=EC=9D=91=EB=8B=B5=20=EC=83=81?=
 =?UTF-8?q?=ED=83=9C=20=EC=BD=94=EB=93=9C=20=EB=B3=80=EA=B2=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

No Content는 본문이 포함되지 않는 것이 표준
---
 nestjs-BE/server/src/spaces/spaces.controller.ts | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/nestjs-BE/server/src/spaces/spaces.controller.ts b/nestjs-BE/server/src/spaces/spaces.controller.ts
index cf2a7170..682351db 100644
--- a/nestjs-BE/server/src/spaces/spaces.controller.ts
+++ b/nestjs-BE/server/src/spaces/spaces.controller.ts
@@ -16,7 +16,6 @@ import {
   Query,
   BadRequestException,
   Delete,
-  HttpCode,
 } from '@nestjs/common';
 import { FileInterceptor } from '@nestjs/platform-express';
 import { SpacesService } from './spaces.service';
@@ -231,7 +230,6 @@ export class SpacesController {
   }
 
   @Delete(':space_uuid/profiles/:profile_uuid')
-  @HttpCode(HttpStatus.NO_CONTENT)
   @ApiOperation({ summary: 'Leave space' })
   @ApiResponse({
     status: HttpStatus.NO_CONTENT,
@@ -259,7 +257,7 @@ export class SpacesController {
     @Req() req: RequestWithUser,
   ) {
     await this.spacesService.leaveSpace(req.user.uuid, profileUuid, spaceUuid);
-    return { statusCode: HttpStatus.NO_CONTENT, message: 'No Content' };
+    return { statusCode: HttpStatus.OK, message: 'OK' };
   }
 
   @Get(':space_uuid/profiles')

From b9915becf45daebd7900515452b3b6c3b2fc6355 Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Mon, 7 Oct 2024 18:33:01 +0900
Subject: [PATCH 24/28] =?UTF-8?q?fix:=20API=20=EC=84=A4=EB=AA=85=20?=
 =?UTF-8?q?=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 nestjs-BE/server/src/spaces/spaces.controller.ts | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/nestjs-BE/server/src/spaces/spaces.controller.ts b/nestjs-BE/server/src/spaces/spaces.controller.ts
index 682351db..a8089ca8 100644
--- a/nestjs-BE/server/src/spaces/spaces.controller.ts
+++ b/nestjs-BE/server/src/spaces/spaces.controller.ts
@@ -235,10 +235,6 @@ export class SpacesController {
     status: HttpStatus.NO_CONTENT,
     description: 'Successfully left the space.',
   })
-  @ApiResponse({
-    status: HttpStatus.BAD_REQUEST,
-    description: 'Profile uuid needed.',
-  })
   @ApiResponse({
     status: HttpStatus.UNAUTHORIZED,
     description: 'User not logged in.',

From ea353ec2ccd6527e87d4dc2a7c00f9d5cbc8cb65 Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Mon, 7 Oct 2024 19:42:43 +0900
Subject: [PATCH 25/28] =?UTF-8?q?test:=20=EC=8A=A4=ED=8E=98=EC=9D=B4?=
 =?UTF-8?q?=EC=8A=A4=EC=97=90=20=EC=B0=B8=EA=B0=80=ED=95=9C=20=ED=94=84?=
 =?UTF-8?q?=EB=A1=9C=ED=95=84=20=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0=20API?=
 =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 nestjs-BE/server/test/spaces.e2e-spec.ts | 72 ++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/nestjs-BE/server/test/spaces.e2e-spec.ts b/nestjs-BE/server/test/spaces.e2e-spec.ts
index 92a49cf7..1a0882b4 100644
--- a/nestjs-BE/server/test/spaces.e2e-spec.ts
+++ b/nestjs-BE/server/test/spaces.e2e-spec.ts
@@ -660,4 +660,76 @@ describe('SpacesController (e2e)', () => {
       .expect(HttpStatus.NOT_FOUND)
       .expect({ message: 'Not Found', statusCode: HttpStatus.NOT_FOUND });
   });
+
+  it('/spaces/:space_uuid/profiles (GET)', async () => {
+    await prisma.profileSpace.create({
+      data: {
+        profileUuid: testProfile.uuid,
+        spaceUuid: testSpace.uuid,
+      },
+    });
+
+    return request(app.getHttpServer())
+      .get(
+        `/spaces/${testSpace.uuid}/profiles?profile_uuid=${testProfile.uuid}`,
+      )
+      .auth(testToken, { type: 'bearer' })
+      .expect(HttpStatus.OK)
+      .expect((res) => {
+        expect(res.body.message).toBe('OK');
+        expect(res.body.statusCode).toBe(HttpStatus.OK);
+        expect(res.body.data).toEqual(expect.arrayContaining([testProfile]));
+      });
+  });
+
+  it('/spaces/:space_uuid/profiles (GET) profile uuid needed', async () => {
+    return request(app.getHttpServer())
+      .get(`/spaces/${testSpace.uuid}/profiles`)
+      .auth(testToken, { type: 'bearer' })
+      .expect(HttpStatus.BAD_REQUEST)
+      .expect({ message: 'Bad Request', statusCode: HttpStatus.BAD_REQUEST });
+  });
+
+  it('/spaces/:space_uuid/profiles (GET) user not logged in', async () => {
+    return request(app.getHttpServer())
+      .get(`/spaces/${testSpace.uuid}/profiles`)
+      .expect(HttpStatus.UNAUTHORIZED)
+      .expect({ message: 'Unauthorized', statusCode: HttpStatus.UNAUTHORIZED });
+  });
+
+  it('/spaces/:space_uuid/profiles (GET) profile user not own', async () => {
+    const newUser = await prisma.user.create({ data: { uuid: uuid() } });
+    const newProfile = await prisma.profile.create({
+      data: {
+        uuid: uuid(),
+        userUuid: newUser.uuid,
+        image: 'test image',
+        nickname: 'test nickname',
+      },
+    });
+
+    return request(app.getHttpServer())
+      .get(`/spaces/${testSpace.uuid}/profiles?profile_uuid=${newProfile.uuid}`)
+      .auth(testToken, { type: 'bearer' })
+      .expect(HttpStatus.FORBIDDEN)
+      .expect({ message: 'Forbidden', statusCode: HttpStatus.FORBIDDEN });
+  });
+
+  it('/spaces/:space_uuid/profiles (GET) profile not joined space', async () => {
+    return request(app.getHttpServer())
+      .get(
+        `/spaces/${testSpace.uuid}/profiles?profile_uuid=${testProfile.uuid}`,
+      )
+      .auth(testToken, { type: 'bearer' })
+      .expect(HttpStatus.FORBIDDEN)
+      .expect({ message: 'Forbidden', statusCode: HttpStatus.FORBIDDEN });
+  });
+
+  it('/spaces/:space_uuid/profiles (GET) profile not found', async () => {
+    return request(app.getHttpServer())
+      .get(`/spaces/${testSpace.uuid}/profiles?profile_uuid=${uuid()}`)
+      .auth(testToken, { type: 'bearer' })
+      .expect(HttpStatus.NOT_FOUND)
+      .expect({ message: 'Not Found', statusCode: HttpStatus.NOT_FOUND });
+  });
 });

From abefa7d86ca9be539d517b4371d6b35dc977188e Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Mon, 7 Oct 2024 19:47:24 +0900
Subject: [PATCH 26/28] =?UTF-8?q?fix:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?=
 =?UTF-8?q?=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 nestjs-BE/server/src/spaces/spaces.controller.spec.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/nestjs-BE/server/src/spaces/spaces.controller.spec.ts b/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
index b7745766..0c096ad9 100644
--- a/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
+++ b/nestjs-BE/server/src/spaces/spaces.controller.spec.ts
@@ -533,8 +533,8 @@ describe('SpacesController', () => {
     );
 
     await expect(response).resolves.toEqual({
-      statusCode: HttpStatus.NO_CONTENT,
-      message: 'No Content',
+      statusCode: HttpStatus.OK,
+      message: 'OK',
     });
   });
 

From 1b78d61d52af9162253b52e0268a091baaf76908 Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Mon, 7 Oct 2024 19:52:37 +0900
Subject: [PATCH 27/28] =?UTF-8?q?fix:=20API=20=EC=84=A4=EB=AA=85=20?=
 =?UTF-8?q?=EC=88=98=EC=A0=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 nestjs-BE/server/src/spaces/spaces.controller.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/nestjs-BE/server/src/spaces/spaces.controller.ts b/nestjs-BE/server/src/spaces/spaces.controller.ts
index a8089ca8..03b3b357 100644
--- a/nestjs-BE/server/src/spaces/spaces.controller.ts
+++ b/nestjs-BE/server/src/spaces/spaces.controller.ts
@@ -273,11 +273,11 @@ export class SpacesController {
   })
   @ApiResponse({
     status: HttpStatus.FORBIDDEN,
-    description: 'Profile user not own.',
+    description: 'Profile user not own. Profile not joined space.',
   })
   @ApiResponse({
     status: HttpStatus.NOT_FOUND,
-    description: 'Profile not found. Profile not joined space.',
+    description: 'Profile not found.',
   })
   async findProfilesInSpace(
     @Param('space_uuid') spaceUuid: string,

From 7a7fe07861593eaf065e15a2de470cf6f092190c Mon Sep 17 00:00:00 2001
From: Conut-1 <1mim1@naver.com>
Date: Mon, 7 Oct 2024 20:09:22 +0900
Subject: [PATCH 28/28] =?UTF-8?q?fix:=20=ED=94=84=EB=A1=9C=ED=95=84=20?=
 =?UTF-8?q?=EC=B0=B8=EA=B0=80=20=EC=97=AC=EB=B6=80=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../profile-space.service.spec.ts             | 39 ++++++++++++++++++-
 .../profile-space/profile-space.service.ts    | 10 +++++
 .../server/src/spaces/spaces.service.spec.ts  | 19 +++++++++
 nestjs-BE/server/src/spaces/spaces.service.ts |  5 +++
 4 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/nestjs-BE/server/src/profile-space/profile-space.service.spec.ts b/nestjs-BE/server/src/profile-space/profile-space.service.spec.ts
index df6aefae..40aa3d28 100644
--- a/nestjs-BE/server/src/profile-space/profile-space.service.spec.ts
+++ b/nestjs-BE/server/src/profile-space/profile-space.service.spec.ts
@@ -1,6 +1,7 @@
 import { Test, TestingModule } from '@nestjs/testing';
 import { ProfileSpaceService } from './profile-space.service';
 import { PrismaService } from '../prisma/prisma.service';
+import { ProfileSpace } from '@prisma/client';
 
 describe('ProfileSpaceService', () => {
   let profileSpaceService: ProfileSpaceService;
@@ -12,7 +13,12 @@ describe('ProfileSpaceService', () => {
         ProfileSpaceService,
         {
           provide: PrismaService,
-          useValue: { profileSpace: { findFirst: jest.fn() } },
+          useValue: {
+            profileSpace: {
+              findFirst: jest.fn(),
+              findUnique: jest.fn(),
+            },
+          },
         },
       ],
     }).compile();
@@ -43,4 +49,35 @@ describe('ProfileSpaceService', () => {
 
     await expect(isSpaceEmpty).resolves.toBeFalsy();
   });
+
+  it('isProfileInSpace joined', async () => {
+    const spaceUuid = 'space uuid';
+    const profileUuid = 'profile uuid';
+    const profileSpaceMock = { profileUuid, spaceUuid } as ProfileSpace;
+
+    (prisma.profileSpace.findUnique as jest.Mock).mockResolvedValue(
+      profileSpaceMock,
+    );
+
+    const isProfileInSpace = profileSpaceService.isProfileInSpace(
+      profileUuid,
+      spaceUuid,
+    );
+
+    await expect(isProfileInSpace).resolves.toBeTruthy();
+  });
+
+  it('isProfileInSpace not joined', async () => {
+    const spaceUuid = 'space uuid';
+    const profileUuid = 'profile uuid';
+
+    (prisma.profileSpace.findUnique as jest.Mock).mockResolvedValue(null);
+
+    const isProfileInSpace = profileSpaceService.isProfileInSpace(
+      profileUuid,
+      spaceUuid,
+    );
+
+    await expect(isProfileInSpace).resolves.toBeFalsy();
+  });
 });
diff --git a/nestjs-BE/server/src/profile-space/profile-space.service.ts b/nestjs-BE/server/src/profile-space/profile-space.service.ts
index 383d8988..851c6f79 100644
--- a/nestjs-BE/server/src/profile-space/profile-space.service.ts
+++ b/nestjs-BE/server/src/profile-space/profile-space.service.ts
@@ -58,4 +58,14 @@ export class ProfileSpaceService {
     });
     return first ? false : true;
   }
+
+  async isProfileInSpace(
+    profileUuid: string,
+    spaceUuid: string,
+  ): Promise<boolean> {
+    const profileSpace = await this.prisma.profileSpace.findUnique({
+      where: { spaceUuid_profileUuid: { spaceUuid, profileUuid } },
+    });
+    return profileSpace ? true : false;
+  }
 }
diff --git a/nestjs-BE/server/src/spaces/spaces.service.spec.ts b/nestjs-BE/server/src/spaces/spaces.service.spec.ts
index 16355fc3..fa7c1237 100644
--- a/nestjs-BE/server/src/spaces/spaces.service.spec.ts
+++ b/nestjs-BE/server/src/spaces/spaces.service.spec.ts
@@ -34,6 +34,7 @@ describe('SpacesService', () => {
             createProfileSpace: jest.fn(),
             deleteProfileSpace: jest.fn(),
             isSpaceEmpty: jest.fn(),
+            isProfileInSpace: jest.fn(),
           },
         },
         {
@@ -272,4 +273,22 @@ describe('SpacesService', () => {
 
     await expect(res).rejects.toThrow(ForbiddenException);
   });
+
+  it('findProfilesInSpace profile not joined space', async () => {
+    const userUuid = 'user uuid';
+    const profileUuid = 'profile uuid';
+    const spaceUuid = 'space uuid';
+
+    (profileSpaceService.isProfileInSpace as jest.Mock).mockResolvedValue(
+      false,
+    );
+
+    const res = spacesService.findProfilesInSpace(
+      userUuid,
+      profileUuid,
+      spaceUuid,
+    );
+
+    await expect(res).rejects.toThrow(ForbiddenException);
+  });
 });
diff --git a/nestjs-BE/server/src/spaces/spaces.service.ts b/nestjs-BE/server/src/spaces/spaces.service.ts
index 26152155..bef2ef57 100644
--- a/nestjs-BE/server/src/spaces/spaces.service.ts
+++ b/nestjs-BE/server/src/spaces/spaces.service.ts
@@ -117,6 +117,11 @@ export class SpacesService {
     spaceUuid: string,
   ): Promise<Profile[]> {
     await this.usersService.verifyUserProfile(userUuid, profileUuid);
+    const isProfileInSpace = await this.profileSpaceService.isProfileInSpace(
+      profileUuid,
+      spaceUuid,
+    );
+    if (!isProfileInSpace) throw new ForbiddenException();
     return this.prisma.profile.findMany({
       where: { spaces: { some: { spaceUuid } } },
     });