diff --git a/apps/api/src/config/config.module.ts b/apps/api/src/config/config.module.ts index dbfcb08..0c78246 100644 --- a/apps/api/src/config/config.module.ts +++ b/apps/api/src/config/config.module.ts @@ -1,14 +1,14 @@ import { Global, Module } from "@nestjs/common"; import { CorsConfigService } from "./cors.config"; -import { JwtConfigService } from "./jwt.config"; /** - * Global configuration module - * Provides configuration services throughout the application + * Global configuration module. + * JWT-config service lives in @cv/core (TokenModule); the apps/api copy + * was stale and has been removed. */ @Global() @Module({ - providers: [JwtConfigService, CorsConfigService], - exports: [JwtConfigService, CorsConfigService], + providers: [CorsConfigService], + exports: [CorsConfigService], }) export class AppConfigModule {} diff --git a/apps/api/src/config/jwt.config.ts b/apps/api/src/config/jwt.config.ts deleted file mode 100644 index 1ff711b..0000000 --- a/apps/api/src/config/jwt.config.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { Injectable } from "@nestjs/common"; -import { ConfigService } from "@nestjs/config"; - -/** - * JWT Configuration Service - * Handles parsing and providing JWT-related configuration values - */ -@Injectable() -export class JwtConfigService { - constructor(private configService: ConfigService) {} - - /** - * Gets the access token expiry string (e.g., "15m") - */ - getAccessTokenExpiry(): string { - return this.configService.getOrThrow("JWT_ACCESS_TOKEN_EXPIRY"); - } - - /** - * Gets the refresh token expiry string (e.g., "7d") - */ - getRefreshTokenExpiry(): string { - return this.configService.getOrThrow("JWT_REFRESH_TOKEN_EXPIRY"); - } - - /** - * Gets the JWT secret - */ - getSecret(): string { - return this.configService.getOrThrow("JWT_SECRET"); - } - - /** - * Calculates expiry date from JWT expiry string format - * Format: number + unit (s=seconds, m=minutes, h=hours, d=days) - * Examples: "15m", "7d", "1h" - */ - calculateExpiryDate(expiryString: string): Date { - const expires_at = new Date(); - - // Parse expiry string (e.g., "15m", "1h", "7d") - // Format is already validated by Joi schema, but we handle edge cases safely - const match = expiryString.match(/^(\d+)([smhd])$/); - if (!(match?.[1] && match[2])) { - // This should never happen due to Joi validation, but provides type safety - expires_at.setMinutes(expires_at.getMinutes() + 15); - return expires_at; - } - - const value = Number.parseInt(match[1], 10); - const unit = match[2]; - - switch (unit) { - case "s": - expires_at.setSeconds(expires_at.getSeconds() + value); - break; - case "m": - expires_at.setMinutes(expires_at.getMinutes() + value); - break; - case "h": - expires_at.setHours(expires_at.getHours() + value); - break; - case "d": - expires_at.setDate(expires_at.getDate() + value); - break; - } - - return expires_at; - } - - /** - * Calculates the access token expiry date - */ - calculateAccessTokenExpiryDate(): Date { - return this.calculateExpiryDate(this.getAccessTokenExpiry()); - } -} diff --git a/apps/api/src/modules/admin/logging-ai-provider.ts b/apps/api/src/modules/admin/logging-ai-provider.ts index 7ecf837..e5f2bea 100644 --- a/apps/api/src/modules/admin/logging-ai-provider.ts +++ b/apps/api/src/modules/admin/logging-ai-provider.ts @@ -1,5 +1,6 @@ import { randomUUID } from "node:crypto"; import { AICompletionRequest, AICompletionResponse, AIProvider, AIProviderStatus } from "@cv/ai-provider"; +import { ClockService } from "@cv/core"; import { AiCallLogService } from "./ai-call-log.service"; interface LoggingOptions { @@ -17,6 +18,7 @@ export class LoggingAIProvider implements AIProvider { constructor( private readonly inner: AIProvider, private readonly logService: AiCallLogService, + private readonly clock: ClockService, private readonly options: LoggingOptions = {}, ) { this.name = inner.name; @@ -31,7 +33,7 @@ export class LoggingAIProvider implements AIProvider { this.logService.record({ id: randomUUID(), - timestamp: new Date().toISOString(), + timestamp: this.clock.now().toISOString(), providerName: this.name, durationMs, promptTokens: response.promptTokens, @@ -49,7 +51,7 @@ export class LoggingAIProvider implements AIProvider { this.logService.record({ id: randomUUID(), - timestamp: new Date().toISOString(), + timestamp: this.clock.now().toISOString(), providerName: this.name, durationMs, status: "error", diff --git a/apps/api/src/modules/admin/queue-monitor.service.ts b/apps/api/src/modules/admin/queue-monitor.service.ts index 16abacb..a453e5d 100644 --- a/apps/api/src/modules/admin/queue-monitor.service.ts +++ b/apps/api/src/modules/admin/queue-monitor.service.ts @@ -1,3 +1,4 @@ +import { ClockService } from "@cv/core"; import { Injectable } from "@nestjs/common"; import { PrismaService } from "@/modules/database/prisma.service"; @@ -48,8 +49,11 @@ export interface WorkerHealthResult { const HEALTHY_THRESHOLD_SECONDS = 60; const STALE_THRESHOLD_SECONDS = 300; -const deriveWorkerStatus = (lastSeenAt: Date): "healthy" | "stale" | "dead" => { - const ageSeconds = (Date.now() - lastSeenAt.getTime()) / 1000; +const deriveWorkerStatus = ( + lastSeenAt: Date, + now: Date, +): "healthy" | "stale" | "dead" => { + const ageSeconds = (now.getTime() - lastSeenAt.getTime()) / 1000; if (ageSeconds <= HEALTHY_THRESHOLD_SECONDS) return "healthy"; if (ageSeconds <= STALE_THRESHOLD_SECONDS) return "stale"; return "dead"; @@ -57,9 +61,10 @@ const deriveWorkerStatus = (lastSeenAt: Date): "healthy" | "stale" | "dead" => { const deriveMessageStatus = ( row: QueueMessageRow, + now: Date, ): "pending" | "scheduled" | "processing" => { if (row.delivered_at) return "processing"; - return row.available_at > new Date() ? "scheduled" : "pending"; + return row.available_at > now ? "scheduled" : "pending"; }; /** @@ -68,7 +73,10 @@ const deriveMessageStatus = ( */ @Injectable() export class QueueMonitorService { - constructor(private readonly prisma: PrismaService) {} + constructor( + private readonly prisma: PrismaService, + private readonly clock: ClockService, + ) {} async getStats(): Promise { const rows = await this.prisma.$queryRaw` @@ -97,11 +105,12 @@ export class QueueMonitorService { FROM queue.messages ORDER BY created_at DESC LIMIT ${clampedLimit} `; + const now = this.clock.now(); return rows.map((row) => ({ id: String(row.id), queueName: row.queue_name, messageName: row.message_name, - status: deriveMessageStatus(row), + status: deriveMessageStatus(row, now), createdAt: row.created_at, })); } @@ -112,9 +121,10 @@ export class QueueMonitorService { FROM queue.worker_heartbeats ORDER BY started_at DESC `; + const now = this.clock.now(); return rows.map((row) => ({ workerId: row.worker_id, - status: deriveWorkerStatus(row.last_seen_at), + status: deriveWorkerStatus(row.last_seen_at, now), startedAt: row.started_at, lastSeenAt: row.last_seen_at, })); diff --git a/apps/api/src/modules/app/app.module.ts b/apps/api/src/modules/app/app.module.ts index a851b79..f8e5ad0 100644 --- a/apps/api/src/modules/app/app.module.ts +++ b/apps/api/src/modules/app/app.module.ts @@ -1,9 +1,11 @@ +import { BaseModule } from "@cv/core"; import { Module } from "@nestjs/common"; import { AppResolver } from "./app.resolver"; import { AppService } from "./app.service"; import { HealthController } from "./health.controller"; @Module({ + imports: [BaseModule], controllers: [HealthController], providers: [AppService, AppResolver], exports: [AppService], diff --git a/apps/api/src/modules/app/app.service.ts b/apps/api/src/modules/app/app.service.ts index fc11559..c1eb738 100644 --- a/apps/api/src/modules/app/app.service.ts +++ b/apps/api/src/modules/app/app.service.ts @@ -1,3 +1,4 @@ +import { ClockService } from "@cv/core"; import { Injectable } from "@nestjs/common"; export interface HealthResponse { @@ -9,15 +10,19 @@ export interface HealthResponse { @Injectable() export class AppService { - private readonly startTime = Date.now(); + private readonly startedAt: Date; + + constructor(private readonly clock: ClockService) { + this.startedAt = clock.now(); + } getHealth(): HealthResponse { - const now = new Date(); + const now = this.clock.now(); return { status: "ok", timestamp: now.toISOString(), timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, - uptime: Date.now() - this.startTime, + uptime: now.getTime() - this.startedAt.getTime(), }; } } diff --git a/apps/api/src/modules/application/application.module.ts b/apps/api/src/modules/application/application.module.ts index 278f10f..f79c44b 100644 --- a/apps/api/src/modules/application/application.module.ts +++ b/apps/api/src/modules/application/application.module.ts @@ -1,5 +1,5 @@ import { AuthModule } from "@cv/auth"; -import { +import { BaseModule, ApplicationMapper, ApplicationPolicy, ApplicationService, @@ -15,7 +15,7 @@ import { ApplicationResolver } from "./graphql/application.resolver"; import { ApplicationUserFieldResolver } from "./graphql/user-field.resolver"; @Module({ - imports: [ + imports: [BaseModule, DatabaseModule, AuthenticationModule, AuthorizationModule, diff --git a/apps/api/src/modules/application/graphql/application.resolver.ts b/apps/api/src/modules/application/graphql/application.resolver.ts index fbee90c..5490084 100644 --- a/apps/api/src/modules/application/graphql/application.resolver.ts +++ b/apps/api/src/modules/application/graphql/application.resolver.ts @@ -1,5 +1,5 @@ import { JwtAuthGuard, VerifiedScopeGuard } from "@cv/auth"; -import { User as DomainUser } from "@cv/core"; +import { ClockService, User as DomainUser } from "@cv/core"; import { Application as ApplicationEntity, ApplicationMapper, ApplicationService, AuthorizationService, PrismaService, } from "@cv/core"; import { UseGuards } from "@nestjs/common"; @@ -34,6 +34,7 @@ export class ApplicationResolver { private readonly cvDataLoader: CVDataLoaderService, private readonly prisma: PrismaService, private readonly authorizationService: AuthorizationService, + private readonly clock: ClockService, ) {} @Query(() => Application, { nullable: true }) @@ -140,7 +141,7 @@ export class ApplicationResolver { }, existingApplication.appliedAt, existingApplication.createdAt, - new Date(), + this.clock.now(), existingApplication.cv, existingApplication.coverLetter, ); diff --git a/apps/api/src/modules/authentication/graphql/authentication.type.ts b/apps/api/src/modules/authentication/graphql/authentication.type.ts index 533f421..6867ff7 100644 --- a/apps/api/src/modules/authentication/graphql/authentication.type.ts +++ b/apps/api/src/modules/authentication/graphql/authentication.type.ts @@ -15,13 +15,13 @@ export class AuthenticationResponse { this.accessTokenExpiration = accessTokenExpiration; } - static fromDomain(domainAuth: { - expires_at: Date; - user: User; - }): AuthenticationResponse { + static fromDomain( + domainAuth: { expires_at: Date; user: User }, + now: Date, + ): AuthenticationResponse { return new AuthenticationResponse( domainAuth.user, - TokenExpiration.fromExpiryDate(domainAuth.expires_at), + TokenExpiration.fromExpiryDate(domainAuth.expires_at, now), ); } } @@ -35,9 +35,12 @@ export class RefreshTokenResponse { this.accessTokenExpiration = accessTokenExpiration; } - static fromDomain(tokens: { expires_at: Date }): RefreshTokenResponse { + static fromDomain( + tokens: { expires_at: Date }, + now: Date, + ): RefreshTokenResponse { return new RefreshTokenResponse( - TokenExpiration.fromExpiryDate(tokens.expires_at), + TokenExpiration.fromExpiryDate(tokens.expires_at, now), ); } } diff --git a/apps/api/src/modules/authentication/providers/password/graphql/password-authentication.resolver.ts b/apps/api/src/modules/authentication/providers/password/graphql/password-authentication.resolver.ts index 03e4c82..8c2c31a 100644 --- a/apps/api/src/modules/authentication/providers/password/graphql/password-authentication.resolver.ts +++ b/apps/api/src/modules/authentication/providers/password/graphql/password-authentication.resolver.ts @@ -1,6 +1,6 @@ import { JwtAuthGuard, VerifiedScopeGuard } from "@cv/auth"; import { - AuthCookieService, AuthorizationService, User as DomainUser, PasswordAuthenticationService, RequestMetadata, } from "@cv/core"; + AuthCookieService, AuthorizationService, ClockService, User as DomainUser, PasswordAuthenticationService, RequestMetadata, } from "@cv/core"; import { UseGuards } from "@nestjs/common"; import { Args, Context, Mutation, Resolver } from "@nestjs/graphql"; import { CurrentUser } from "@/modules/current-user/current-user.decorator"; @@ -14,6 +14,7 @@ export class PasswordAuthenticationResolver { private readonly passwordAuthenticationService: PasswordAuthenticationService, private readonly authorizationService: AuthorizationService, private readonly authCookieService: AuthCookieService, + private readonly clock: ClockService, ) {} @Mutation(() => AuthenticationResponse) @@ -34,10 +35,13 @@ export class PasswordAuthenticationResolver { result.refresh_token, ); - return AuthenticationResponse.fromDomain({ - expires_at: result.expires_at, - user: User.fromDomain(result.user), - }); + return AuthenticationResponse.fromDomain( + { + expires_at: result.expires_at, + user: User.fromDomain(result.user), + }, + this.clock.now(), + ); } @Mutation(() => AuthenticationResponse) @@ -64,10 +68,13 @@ export class PasswordAuthenticationResolver { ); } - return AuthenticationResponse.fromDomain({ - expires_at: result.expires_at, - user: User.fromDomain(result.user), - }); + return AuthenticationResponse.fromDomain( + { + expires_at: result.expires_at, + user: User.fromDomain(result.user), + }, + this.clock.now(), + ); } @Mutation(() => Boolean) @@ -127,10 +134,13 @@ export class PasswordAuthenticationResolver { result.refresh_token, ); - return AuthenticationResponse.fromDomain({ - expires_at: result.expires_at, - user: User.fromDomain(result.user), - }); + return AuthenticationResponse.fromDomain( + { + expires_at: result.expires_at, + user: User.fromDomain(result.user), + }, + this.clock.now(), + ); } @Mutation(() => Boolean) @@ -153,10 +163,14 @@ export class PasswordAuthenticationResolver { requestMetadata, ); this.authCookieService.setAuthCookies(res, access_token, refresh_token); - return AuthenticationResponse.fromDomain({ - expires_at, - user: User.fromDomain(user), - }); + return AuthenticationResponse.fromDomain( + { + expires_at, + user: User.fromDomain(user), + }, + this.clock.now(), + ); } } + diff --git a/apps/api/src/modules/authentication/providers/password/password-provider.module.ts b/apps/api/src/modules/authentication/providers/password/password-provider.module.ts index 204badc..1fb5009 100644 --- a/apps/api/src/modules/authentication/providers/password/password-provider.module.ts +++ b/apps/api/src/modules/authentication/providers/password/password-provider.module.ts @@ -1,4 +1,5 @@ import { + BaseModule, PasswordProviderModule as AuthPasswordProviderModule, EMAIL_CONFIG_TOKEN, EmailConfig, @@ -12,7 +13,7 @@ import { ConfigModule, ConfigService } from "@nestjs/config"; import { PasswordAuthenticationResolver } from "./graphql/password-authentication.resolver"; @Module({ - imports: [ConfigModule, AuthPasswordProviderModule], + imports: [ConfigModule, BaseModule, AuthPasswordProviderModule], providers: [ PasswordAuthenticationResolver, { diff --git a/apps/api/src/modules/authentication/rest/authentication.controller.ts b/apps/api/src/modules/authentication/rest/authentication.controller.ts index a8fe9a5..d67439f 100644 --- a/apps/api/src/modules/authentication/rest/authentication.controller.ts +++ b/apps/api/src/modules/authentication/rest/authentication.controller.ts @@ -1,5 +1,5 @@ import { - AuthCookieService, AuthenticationService, RequestMetadata, } from "@cv/core"; + AuthCookieService, AuthenticationService, ClockService, RequestMetadata, } from "@cv/core"; import { Controller, Post, Res } from "@nestjs/common"; import type { Response } from "express"; import { RefreshTokenCookie } from "../token/refresh-token-cookie.decorator"; @@ -11,6 +11,7 @@ export class AuthenticationController { constructor( private readonly authenticationService: AuthenticationService, private readonly authCookieService: AuthCookieService, + private readonly clock: ClockService, ) {} @Post("credentials/refresh") @@ -32,6 +33,7 @@ export class AuthenticationController { const accessTokenExpiration = TokenExpiration.fromExpiryDate( result.expires_at, + this.clock.now(), ); return new RefreshTokenResponseDto({ diff --git a/apps/api/src/modules/authentication/token/token-expiration.type.ts b/apps/api/src/modules/authentication/token/token-expiration.type.ts index 892cd5a..b3ead7d 100644 --- a/apps/api/src/modules/authentication/token/token-expiration.type.ts +++ b/apps/api/src/modules/authentication/token/token-expiration.type.ts @@ -13,8 +13,7 @@ export class TokenExpiration { this.expiresInSeconds = expiresInSeconds; } - static fromExpiryDate(expiresAt: Date): TokenExpiration { - const now = new Date(); + static fromExpiryDate(expiresAt: Date, now: Date): TokenExpiration { const expiresInSeconds = Math.max( 0, Math.floor((expiresAt.getTime() - now.getTime()) / 1000), diff --git a/apps/api/src/modules/cv-parser/ai-provider-resolver.service.ts b/apps/api/src/modules/cv-parser/ai-provider-resolver.service.ts index afcd77b..17ac031 100644 --- a/apps/api/src/modules/cv-parser/ai-provider-resolver.service.ts +++ b/apps/api/src/modules/cv-parser/ai-provider-resolver.service.ts @@ -1,7 +1,7 @@ import { randomUUID } from "node:crypto"; import { AI_PROVIDER, AIProvider, AnthropicProvider, OpenAIProvider, } from "@cv/ai-provider"; -import { User } from "@cv/core"; +import { ClockService, User } from "@cv/core"; import { BadRequestException, ForbiddenException, @@ -29,6 +29,7 @@ export class AIProviderResolverService { private readonly globalProvider: AIProvider | undefined, private readonly userAiSettingsService: UserAiSettingsService, private readonly aiCallLogService: AiCallLogService, + private readonly clock: ClockService, ) {} async resolveForUser(user: User): Promise { @@ -37,7 +38,7 @@ export class AIProviderResolverService { } catch (err) { this.aiCallLogService.record({ id: randomUUID(), - timestamp: new Date().toISOString(), + timestamp: this.clock.now().toISOString(), providerName: "resolution", durationMs: 0, status: "error", @@ -64,10 +65,15 @@ export class AIProviderResolverService { "Platform AI is not available. Configure your own provider in profile settings.", ); } - return new LoggingAIProvider(this.globalProvider, this.aiCallLogService, { - userId: user.id, - source: "platform", - }); + return new LoggingAIProvider( + this.globalProvider, + this.aiCallLogService, + this.clock, + { + userId: user.id, + source: "platform", + }, + ); } const resolved = @@ -104,7 +110,7 @@ export class AIProviderResolverService { ); })(); - return new LoggingAIProvider(provider, this.aiCallLogService, { + return new LoggingAIProvider(provider, this.aiCallLogService, this.clock, { userId, source: "byok", }); diff --git a/apps/api/src/modules/cv-parser/cv-parser.module.ts b/apps/api/src/modules/cv-parser/cv-parser.module.ts index fc4121e..85b1120 100644 --- a/apps/api/src/modules/cv-parser/cv-parser.module.ts +++ b/apps/api/src/modules/cv-parser/cv-parser.module.ts @@ -3,7 +3,7 @@ import { mkdirSync } from "node:fs"; import { join } from "node:path"; import { CVParserModule as CVParserCoreModule } from "@cv/ai-parser"; import { AIModule } from "@cv/ai-provider"; -import { DatabaseModule } from "@cv/core"; +import { BaseModule, DatabaseModule } from "@cv/core"; import { FileExtractionModule } from "@cv/file-upload"; import { Module } from "@nestjs/common"; import { MulterModule } from "@nestjs/platform-express"; @@ -23,7 +23,7 @@ import { UploadFileResolver } from "./graphql/upload-file.resolver"; import { ImportOnboardingStep } from "./onboarding/import.step"; @Module({ - imports: [ + imports: [BaseModule, CVParserCoreModule.forConfig(), AIModule.forConfig(), FileExtractionModule.forRoot(), diff --git a/apps/api/src/modules/cv-template/graphql/cv-template.resolver.ts b/apps/api/src/modules/cv-template/graphql/cv-template.resolver.ts index 692c99d..0bf80be 100644 --- a/apps/api/src/modules/cv-template/graphql/cv-template.resolver.ts +++ b/apps/api/src/modules/cv-template/graphql/cv-template.resolver.ts @@ -1,5 +1,5 @@ import { JwtAuthGuard, VerifiedScopeGuard } from "@cv/auth"; -import { AuthorizationService, CV as CVEntity, CVRendererService, CVService, CVTemplateService, User as DomainUser, PaginationService, UuidFactoryService } from "@cv/core"; +import { ClockService, AuthorizationService, CV as CVEntity, CVRendererService, CVService, CVTemplateService, User as DomainUser, PaginationService, UuidFactoryService } from "@cv/core"; import { UseGuards } from "@nestjs/common"; import { Args, Mutation, Query, Resolver } from "@nestjs/graphql"; import { CurrentUser } from "@/modules/current-user/current-user.decorator"; @@ -19,6 +19,7 @@ export class CVTemplateResolver { private readonly cvTemplateService: CVTemplateService, private readonly paginationService: PaginationService, private readonly authorizationService: AuthorizationService, + private readonly clock: ClockService, ) {} @Query(() => CVTemplateConnection) @@ -58,6 +59,7 @@ export class CVResolver { private readonly uuidFactory: UuidFactoryService, readonly _paginationService: PaginationService, private readonly authorizationService: AuthorizationService, + private readonly clock: ClockService, ) {} @Query(() => CV, { nullable: true }) @@ -93,7 +95,7 @@ export class CVResolver { const template = await this.cvTemplateService.findByIdOrFail( input.templateId, ); - const now = new Date(); + const now = this.clock.now(); const cv = new CV( this.uuidFactory.generate(), input.profileId, @@ -126,7 +128,7 @@ export class CVResolver { existing.profileId, input.title ?? existing.title, existing.createdAt, - new Date(), + this.clock.now(), template, input.introduction === undefined ? existing.introduction : input.introduction, ); diff --git a/apps/api/src/modules/job-experience/company/graphql/company.resolver.ts b/apps/api/src/modules/job-experience/company/graphql/company.resolver.ts index 0b643df..c56b7d0 100644 --- a/apps/api/src/modules/job-experience/company/graphql/company.resolver.ts +++ b/apps/api/src/modules/job-experience/company/graphql/company.resolver.ts @@ -1,5 +1,5 @@ import { JwtAuthGuard, VerifiedScopeGuard } from "@cv/auth"; -import { User as DomainUser } from "@cv/core"; +import { ClockService, User as DomainUser } from "@cv/core"; import { AuthorizationService, Company, Company as CompanyEntity, CompanyFactory, CompanyService, PaginationService, } from "@cv/core"; import { UseGuards } from "@nestjs/common"; @@ -16,6 +16,7 @@ export class CompanyResolver { private readonly companyFactory: CompanyFactory, private readonly paginationService: PaginationService, private readonly authorizationService: AuthorizationService, + private readonly clock: ClockService, ) {} @Query(() => CompanyConnection) @@ -99,7 +100,7 @@ export class CompanyResolver { company.id, dto.name ?? company.name, company.createdAt, - new Date(), + this.clock.now(), dto.description !== undefined ? dto.description : company.description, dto.website !== undefined ? dto.website : company.website, ); diff --git a/apps/api/src/modules/job-experience/level/graphql/level.resolver.ts b/apps/api/src/modules/job-experience/level/graphql/level.resolver.ts index 338e4dd..c4be94a 100644 --- a/apps/api/src/modules/job-experience/level/graphql/level.resolver.ts +++ b/apps/api/src/modules/job-experience/level/graphql/level.resolver.ts @@ -1,5 +1,5 @@ import { JwtAuthGuard, VerifiedScopeGuard } from "@cv/auth"; -import { User as DomainUser } from "@cv/core"; +import { ClockService, User as DomainUser } from "@cv/core"; import { AuthorizationService, Level as LevelEntity, LevelFactory, LevelService, PaginationService, } from "@cv/core"; import { UseGuards } from "@nestjs/common"; @@ -16,6 +16,7 @@ export class LevelResolver { private readonly levelFactory: LevelFactory, private readonly paginationService: PaginationService, private readonly authorizationService: AuthorizationService, + private readonly clock: ClockService, ) {} @Query(() => LevelConnection) @@ -85,7 +86,7 @@ export class LevelResolver { level.id, dto.name ?? level.name, level.createdAt, - new Date(), + this.clock.now(), dto.description !== undefined ? dto.description : level.description, ); const domainLevel = await this.levelService.save(updatedEntity); diff --git a/apps/api/src/modules/job-experience/role/graphql/role.resolver.ts b/apps/api/src/modules/job-experience/role/graphql/role.resolver.ts index 37fad73..20ffbd1 100644 --- a/apps/api/src/modules/job-experience/role/graphql/role.resolver.ts +++ b/apps/api/src/modules/job-experience/role/graphql/role.resolver.ts @@ -1,5 +1,5 @@ import { JwtAuthGuard, VerifiedScopeGuard } from "@cv/auth"; -import { User as DomainUser } from "@cv/core"; +import { ClockService, User as DomainUser } from "@cv/core"; import { AuthorizationService, PaginationService, Role as RoleEntity, RoleFactory, RoleService, } from "@cv/core"; import { UseGuards } from "@nestjs/common"; @@ -16,6 +16,7 @@ export class RoleResolver { private readonly roleFactory: RoleFactory, private readonly paginationService: PaginationService, private readonly authorizationService: AuthorizationService, + private readonly clock: ClockService, ) {} @Query(() => RoleConnection) @@ -83,7 +84,7 @@ export class RoleResolver { role.id, dto.name ?? role.name, role.createdAt, - new Date(), + this.clock.now(), dto.description !== undefined ? dto.description : role.description, ); const domainRole = await this.roleService.save(updatedEntity); diff --git a/apps/api/src/modules/job-experience/skill/graphql/skill.resolver.ts b/apps/api/src/modules/job-experience/skill/graphql/skill.resolver.ts index 39e3846..2fca253 100644 --- a/apps/api/src/modules/job-experience/skill/graphql/skill.resolver.ts +++ b/apps/api/src/modules/job-experience/skill/graphql/skill.resolver.ts @@ -1,5 +1,5 @@ import { JwtAuthGuard, VerifiedScopeGuard } from "@cv/auth"; -import { User as DomainUser } from "@cv/core"; +import { ClockService, User as DomainUser } from "@cv/core"; import { AuthorizationService, PaginationService, Skill as SkillEntity, SkillFactory, SkillService, } from "@cv/core"; import { UseGuards } from "@nestjs/common"; @@ -16,6 +16,7 @@ export class SkillResolver { private readonly skillFactory: SkillFactory, private readonly paginationService: PaginationService, private readonly authorizationService: AuthorizationService, + private readonly clock: ClockService, ) {} @Query(() => SkillConnection) @@ -85,7 +86,7 @@ export class SkillResolver { skill.id, dto.name ?? skill.name, skill.createdAt, - new Date(), + this.clock.now(), dto.description !== undefined ? dto.description : skill.description, ); const domainSkill = await this.skillService.save(updatedEntity); diff --git a/apps/api/src/modules/organization/graphql/organization.resolver.ts b/apps/api/src/modules/organization/graphql/organization.resolver.ts index b8c680c..e18f251 100644 --- a/apps/api/src/modules/organization/graphql/organization.resolver.ts +++ b/apps/api/src/modules/organization/graphql/organization.resolver.ts @@ -1,5 +1,5 @@ import { JwtAuthGuard, VerifiedScopeGuard } from "@cv/auth"; -import { User as DomainUser, Membership } from "@cv/core"; +import { ClockService, User as DomainUser, Membership } from "@cv/core"; import { AuthorizationService, MembershipSortField, MembershipSortOrder, Organization, OrganizationFactory, OrganizationService, PaginationService, UserService, } from "@cv/core"; import { UseGuards } from "@nestjs/common"; @@ -23,6 +23,7 @@ export class OrganizationResolver { private readonly organizationFactory: OrganizationFactory, private readonly paginationService: PaginationService, private readonly authorizationService: AuthorizationService, + private readonly clock: ClockService, private readonly userService: UserService, ) {} @@ -114,7 +115,7 @@ export class OrganizationResolver { organization.id, dto.name ?? organization.name, organization.createdAt, - new Date(), + this.clock.now(), dto.description !== undefined ? dto.description : organization.description,