Skip to content

Commit 1ca0597

Browse files
authored
사용자 로그인 시 로그인 이벤트 수집 (#38)
feat: sign in event 수집
1 parent a27fc1e commit 1ca0597

File tree

7 files changed

+43
-4
lines changed

7 files changed

+43
-4
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- AlterTable
2+
ALTER TABLE "account" ADD COLUMN "lastSignedInAt" TIMESTAMP(3);

prisma/schema.prisma

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@ model Account {
2828
role AccountRole
2929
signInType SignInType
3030
31-
username String? @unique @db.VarChar(20)
32-
password String?
33-
lastEnteredAt DateTime? @db.Timestamp(3)
31+
username String? @unique @db.VarChar(20)
32+
password String?
33+
lastEnteredAt DateTime? @db.Timestamp(3)
34+
lastSignedInAt DateTime? @db.Timestamp(3)
3435
3536
createdAt DateTime @default(now()) @db.Timestamp(3)
3637
updatedAt DateTime @updatedAt @db.Timestamp(3)

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { AccountCreatedEvent } from '@module/account/events/account-created-event/account-created.event';
22
import { AccountEnteredEvent } from '@module/account/events/account-entered-event/account-entered.event';
3+
import { AccountSignedInEvent } from '@module/account/events/account-signed-in-event/account-signed-in.event';
34

45
import {
56
AggregateRoot,
@@ -22,6 +23,7 @@ export interface AccountProps {
2223
username?: string;
2324
password?: string;
2425
enteredAt?: Date;
26+
lastSignedInAt?: Date;
2527
}
2628

2729
interface CreateAccountProps {
@@ -95,4 +97,14 @@ export class Account extends AggregateRoot<AccountProps> {
9597

9698
this.apply(new AccountEnteredEvent(this.id, { enteredAt: now }));
9799
}
100+
101+
signIn() {
102+
const now = new Date();
103+
104+
this.props.lastSignedInAt = now;
105+
106+
this.updatedAt = now;
107+
108+
this.apply(new AccountSignedInEvent(this.id, { signedInAt: now }));
109+
}
98110
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { DomainEvent } from '@common/base/base.domain-event';
2+
3+
interface AccountSignedInEventPayload {
4+
signedInAt: Date;
5+
}
6+
7+
export class AccountSignedInEvent extends DomainEvent<AccountSignedInEventPayload> {
8+
readonly aggregate = 'Account';
9+
}

src/modules/account/mappers/account.mapper.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export class AccountMapper extends BaseMapper {
1919
username: raw.username ?? undefined,
2020
password: raw.password ?? undefined,
2121
enteredAt: raw.lastEnteredAt ?? undefined,
22+
lastSignedInAt: raw.lastSignedInAt ?? undefined,
2223
},
2324
});
2425
}
@@ -33,6 +34,7 @@ export class AccountMapper extends BaseMapper {
3334
username: entity.props.username ?? null,
3435
password: entity.props.password ?? null,
3536
lastEnteredAt: entity.props.enteredAt ?? null,
37+
lastSignedInAt: entity.props.lastSignedInAt ?? null,
3638
};
3739
}
3840
}

src/modules/auth/use-cases/sign-in-with-username/__spec__/sign-in-with-username.handler.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import { SignInWithUsernameCommandFactory } from '@module/auth/use-cases/sign-in
1313
import { SignInWithUsernameCommand } from '@module/auth/use-cases/sign-in-with-username/sign-in-with-username.command';
1414
import { SignInWithUsernameHandler } from '@module/auth/use-cases/sign-in-with-username/sign-in-with-username.handler';
1515

16+
import { EventStoreModule } from '@core/event-sourcing/event-store.module';
17+
1618
describe(SignInWithUsernameHandler, () => {
1719
let handler: SignInWithUsernameHandler;
1820

@@ -22,7 +24,7 @@ describe(SignInWithUsernameHandler, () => {
2224

2325
beforeEach(async () => {
2426
const module: TestingModule = await Test.createTestingModule({
25-
imports: [CqrsModule, AuthTokenModule],
27+
imports: [CqrsModule, AuthTokenModule, EventStoreModule],
2628
providers: [SignInWithUsernameHandler],
2729
}).compile();
2830

src/modules/auth/use-cases/sign-in-with-username/sign-in-with-username.handler.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,19 @@ import {
1313
} from '@module/auth/services/auth-token/auth-token.service.interface';
1414
import { SignInWithUsernameCommand } from '@module/auth/use-cases/sign-in-with-username/sign-in-with-username.command';
1515

16+
import {
17+
EVENT_STORE,
18+
IEventStore,
19+
} from '@core/event-sourcing/event-store.interface';
20+
1621
@CommandHandler(SignInWithUsernameCommand)
1722
export class SignInWithUsernameHandler
1823
implements ICommandHandler<SignInWithUsernameCommand, AuthToken>
1924
{
2025
constructor(
2126
private readonly queryBus: QueryBus,
27+
@Inject(EVENT_STORE)
28+
private readonly eventStore: IEventStore,
2229
@Inject(AUTH_TOKEN_SERVICE)
2330
private readonly authService: IAuthTokenService,
2431
) {}
@@ -47,8 +54,12 @@ export class SignInWithUsernameHandler
4754
throw new SignInInfoNotMatchedError();
4855
}
4956

57+
account.signIn();
58+
5059
const authToken = this.authService.generateAuthToken(account);
5160

61+
await this.eventStore.storeAggregateEvents(account);
62+
5263
return authToken;
5364
}
5465
}

0 commit comments

Comments
 (0)