Skip to content

Commit 2977c39

Browse files
authored
계정 속성에 nickname 추가 (#48)
* feat: 계정 속성에 nickname 추가 계정 생성 시 닉네임이 존재하지 않는다면 tsid로 폴백처리 * feat: 계정 입장 이벤트 속성에 nickname 추가
1 parent c480519 commit 2977c39

File tree

20 files changed

+142
-5
lines changed

20 files changed

+142
-5
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
마이그레이션 절차:
3+
1) 닉네임 컬럼 추가 (nullable)
4+
2) 기존 row의 nickname = id::text 로 백필
5+
3) NOT NULL + UNIQUE 제약 추가
6+
*/
7+
8+
-- Step 1
9+
ALTER TABLE "account" ADD COLUMN "nickname" VARCHAR(20);
10+
11+
-- Step 2
12+
UPDATE "account"
13+
SET "nickname" = "id"::text
14+
WHERE "nickname" IS NULL;
15+
16+
-- Step 3
17+
ALTER TABLE "account" ALTER COLUMN "nickname" SET NOT NULL;
18+
19+
CREATE UNIQUE INDEX "account_nickname_key" ON "account"("nickname");

prisma/schema.prisma

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ model Account {
3030
3131
username String? @unique @db.VarChar(20)
3232
password String?
33+
nickname String @unique @db.VarChar(20)
3334
lastEnteredAt DateTime? @db.Timestamp(3)
3435
lastSignedInAt DateTime? @db.Timestamp(3)
3536

src/modules/account/assemblers/account-dto.assembler.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export class AccountDtoAssembler {
1111

1212
dto.role = account.role;
1313
dto.signInType = account.signInType;
14+
dto.nickname = account.nickname;
1415
dto.enteredAt = account.enteredAt;
1516

1617
return dto;

src/modules/account/dto/account.dto.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ export class AccountDto extends BaseResponseDto {
2020
})
2121
signInType: SignInType;
2222

23+
@ApiProperty()
24+
nickname: string;
25+
2326
@ApiProperty({
2427
description: '진입 시점',
2528
})

src/modules/account/entities/__spec__/account.factory.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export const AccountFactory = Factory.define<Account & AccountProps>(
1919
signInType: () => faker.helpers.arrayElement(Object.values(SignInType)),
2020
username: () => faker.internet.username(),
2121
password: () => faker.internet.password(),
22+
nickname: () => generateEntityId(),
2223
enteredAt: () => faker.date.past(),
2324
createdAt: () => new Date(),
2425
updatedAt: () => new Date(),

src/modules/account/entities/account.entity.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@ export interface AccountProps {
2222
signInType: SignInType;
2323
username?: string;
2424
password?: string;
25+
nickname: string;
2526
enteredAt?: Date;
2627
lastSignedInAt?: Date;
2728
}
2829

2930
interface CreateAccountProps {
3031
role: AccountRole;
3132
signInType: SignInType;
33+
nickname?: string;
3234
username?: string;
3335
password?: string;
3436
}
@@ -49,6 +51,7 @@ export class Account extends AggregateRoot<AccountProps> {
4951
signInType: props.signInType,
5052
username: props.username,
5153
password: props.password,
54+
nickname: props.nickname ?? generateEntityId(),
5255
},
5356
createdAt: date,
5457
updatedAt: date,
@@ -60,6 +63,7 @@ export class Account extends AggregateRoot<AccountProps> {
6063
signInType: props.signInType,
6164
username: props.username,
6265
password: props.password,
66+
nickname: account.props.nickname,
6367
}),
6468
);
6569

@@ -84,6 +88,10 @@ export class Account extends AggregateRoot<AccountProps> {
8488
return this.props.password;
8589
}
8690

91+
get nickname(): string {
92+
return this.props.nickname;
93+
}
94+
8795
get enteredAt(): Date | undefined {
8896
return this.props.enteredAt;
8997
}
@@ -95,7 +103,12 @@ export class Account extends AggregateRoot<AccountProps> {
95103

96104
this.updatedAt = now;
97105

98-
this.apply(new AccountEnteredEvent(this.id, { enteredAt: now }));
106+
this.apply(
107+
new AccountEnteredEvent(this.id, {
108+
nickname: this.props.nickname,
109+
enteredAt: now,
110+
}),
111+
);
99112
}
100113

101114
signIn() {
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { BaseError } from '@common/base/base.error';
2+
3+
export class AccountNicknameAlreadyOccupiedError extends BaseError {
4+
static CODE: string = 'ACCOUNT.NICKNAME_ALREADY_OCCUPIED';
5+
6+
constructor(message?: string) {
7+
super(
8+
message ?? 'Account nickname is already occupied',
9+
AccountNicknameAlreadyOccupiedError.CODE,
10+
);
11+
}
12+
}

src/modules/account/events/account-created-event/account-created.event.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ interface AccountCreatedEventPayload {
1010
signInType: SignInType;
1111
username?: string;
1212
password?: string;
13+
nickname: string;
1314
}
1415

1516
export class AccountCreatedEvent extends DomainEvent<AccountCreatedEventPayload> {

src/modules/account/events/account-entered-event/__spec__/account-entered.handler.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ describe(AccountEnteredHandler, () => {
5454

5555
beforeEach(() => {
5656
event = new AccountEnteredEvent(generateEntityId(), {
57+
nickname: generateEntityId(),
5758
enteredAt: new Date(),
5859
});
5960
});

src/modules/account/events/account-entered-event/account-entered.event.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { DomainEvent } from '@common/base/base.domain-event';
22

33
interface AccountEnteredEventPayload {
4+
nickname: string;
45
enteredAt: Date;
56
}
67

0 commit comments

Comments
 (0)