diff --git a/apidesign/boilerplate-api-documentation/docs/openapi.yaml b/apidesign/boilerplate-api-documentation/docs/openapi.yaml index ee97284..c3d5389 100644 --- a/apidesign/boilerplate-api-documentation/docs/openapi.yaml +++ b/apidesign/boilerplate-api-documentation/docs/openapi.yaml @@ -1,4 +1,4 @@ -openapi: 3.1.0 +openapi: 3.1.0 info: title: D-Shiftify API & Documentation version: 1.0.0 @@ -1298,47 +1298,111 @@ paths: schema: type: object required: - - job_type - - work_mode + - profileId + - jobType + - workMode - mobility - - expected_job + - expectedJob properties: - job_type: + profileId: type: string - example: "Full-time" - work_mode: + format: uuid + example: "9d83050f-3040-4c04-946e-504d3f34fdea" + jobType: + type: string + example: "Fulltime" + workMode: type: string example: "Remote" mobility: type: string - example: "Su dung xe lan" - expected_job: + example: "Wheelchair" + expectedJob: type: string - example: "Nhan vien nhap lieu" - conditions: - type: object - properties: - prefer_near_home: { type: boolean, example: true } - prefer_low_traffic: { type: boolean, example: true } - prefer_good_company: { type: boolean, example: true } - experiences: + example: "Backend Developer" + deviceIds: + type: array + items: + type: string + format: uuid + example: + - "905c9a98-8f51-4296-84b3-d521ece0d1a2" + - "e4a8d1b5-ac6a-455f-8027-aaa1a4489839" + - "9d1dda30-7361-45c3-8b79-db9629888080" + skills: type: array items: type: object properties: - description: { type: string, example: "Thuc tap sinh tai The Code Origin" } - working_time: { type: string, example: "3 thang" } - skills: + name: + type: string + example: "Communication" + type: + type: string + enum: + - soft_skill + - hard_skill + example: "soft_skill" + example: + - name: "Communication" + type: "soft_skill" + - name: "NodeJS" + type: "hard_skill" + conditions: type: array items: type: string - format: uuid - example: ["uuid-skill-1", "uuid-skill-2"] + example: + - "Ưu tiên công ty hỗ trợ người khuyết tật" + - "Ưu tiên khu vực ít giao thông" + experiences: + type: array + items: + type: object + properties: + description: + type: string + example: "Developed REST APIs using ExpressJS" + company: + type: string + example: "FPT Software" + position: + type: string + example: "Backend Intern" + startDate: + type: string + example: "2024-01" + endDate: + type: string + example: "2024-06" + example: + - description: "Developed REST APIs using ExpressJS" + company: "FPT Software" + position: "Backend Intern" + startDate: "2024-01" + endDate: "2024-06" certificates: type: array items: type: string - example: ["Chung chi Tin hoc van phong A"] + example: + - "IELTS 6.5" + customSections: + type: array + items: + type: object + properties: + title: + type: string + example: "Education" + content: + type: string + example: "Duy Tan University - Software Engineering" + example: + - title: "Education" + content: "Duy Tan University - Software Engineering" + - title: "Career Objective" + content: "Become a backend developer." responses: "201": description: CV created successfully @@ -1458,50 +1522,139 @@ paths: type: object required: - id - - profile - - job_type - - work_mode + - profileId + - jobType + - workMode - mobility - - expected_job - - updated_at + - expectedJob + - skills + - conditions + - experiences + - certificates + - customSections + - createdAt + - updatedAt + - fullName + - phone + - gender + - disabilityStatus + - email properties: - id: { type: string, format: uuid, example: "8e5e9334-..." } - profile: - type: object - properties: - full_name: { type: string, example: "Pham Hoang Vu" } - disability_status: { type: string, example: "Khiem thinh nhe" } - job_type: { type: string, example: "Full-time" } - work_mode: { type: string, example: "Remote" } - mobility: { type: string, example: "Su dung xe lan" } - expected_job: { type: string, example: "Nhan vien nhap lieu" } - conditions: - type: object - properties: - prefer_near_home: { type: boolean, example: true } - prefer_low_traffic: { type: boolean, example: true } - prefer_good_company: { type: boolean, example: true } - experiences: + id: + type: string + format: uuid + example: "702a5921-e145-41e1-9fad-705ec6292f42" + profileId: + type: string + format: uuid + example: "9d83050f-3040-4c04-946e-504d3f34fdea" + jobType: + type: string + example: "Fulltime" + workMode: + type: string + example: "Remote" + mobility: + type: string + example: "Wheelchair" + expectedJob: + type: string + example: "Backend Developer" + skills: type: array items: type: object properties: - description: { type: string, example: "Thuc tap sinh tai The Code Origin" } - working_time: { type: string, example: "3 thang" } - skills: + name: + type: string + example: "Communication" + type: + type: string + enum: ["soft_skill", "hard_skill"] + example: "soft_skill" + example: + - name: "Communication" + type: "soft_skill" + - name: "NodeJS" + type: "hard_skill" + conditions: + type: array + items: + type: string + example: + - "Ưu tiên công ty hỗ trợ người khuyết tật" + - "Ưu tiên khu vực ít giao thông" + experiences: type: array items: type: object properties: - id: { type: string, example: "uuid-1" } - name: { type: string, example: "Node.js" } - type: { type: string, example: "hard" } + company: + type: string + example: "FPT Software" + endDate: + type: string + example: "2024-06" + position: + type: string + example: "Backend Intern" + startDate: + type: string + example: "2024-01" + description: + type: string + example: "Developed REST APIs using ExpressJS" + example: + - company: "FPT Software" + endDate: "2024-06" + position: "Backend Intern" + startDate: "2024-01" + description: "Developed REST APIs using ExpressJS" certificates: type: array items: type: string - example: ["Chung chi Tin hoc van phong A"] - updated_at: { type: string, format: date-time, example: "2024-04-15T10:00:00Z" } + example: + - "IELTS 6.5" + customSections: + type: array + items: + type: object + properties: + title: + type: string + example: "Education" + content: + type: string + example: "Duy Tan University - Software Engineering" + example: + - title: "Education" + content: "Duy Tan University - Software Engineering" + - title: "Career Objective" + content: "Become a backend developer." + createdAt: + type: string + format: date-time + example: "2026-05-13T06:55:23.598Z" + updatedAt: + type: string + format: date-time + example: "2026-05-13T06:55:23.598Z" + fullName: + type: string + example: "Candidate 1" + phone: + type: string + example: "0901000000" + gender: + type: string + example: "male" + disabilityStatus: + type: string + example: "visual_impairment" + email: + type: string + example: "candidate1@example.com" "404": description: Not Found content: @@ -1656,7 +1809,6 @@ paths: properties: status: { type: string, example: "error" } message: { type: string, example: "Unauthenticated" } - # --- Job --- /api/v1/jobs: post: diff --git a/backend/src/core/api/cv/cv.controller.js b/backend/src/core/api/cv/cv.controller.js new file mode 100644 index 0000000..d957945 --- /dev/null +++ b/backend/src/core/api/cv/cv.controller.js @@ -0,0 +1,29 @@ +import { ValidHttpResponse } from 'packages/handler/response/validHttp.response'; +import { CVService } from 'core/modules/cv/service/cv.service'; + +class Controller { + constructor() { + this.service = CVService; + } + + createOne = async req => { + const data = await this.service.createOne(req.body); + + return ValidHttpResponse.toCreatedResponse(data); + }; + + findById = async req => { + const data = await this.service.getCvById(req.params.id); + + return ValidHttpResponse.toOkResponse(data); + }; + + updateCV = async req => { + const data = await this.service.updateCV(req.params.id, req.body); + + return ValidHttpResponse.toOkResponse(data); + }; + +} + +export const CVController = new Controller(); \ No newline at end of file diff --git a/backend/src/core/api/cv/cv.resolver.js b/backend/src/core/api/cv/cv.resolver.js new file mode 100644 index 0000000..ad076aa --- /dev/null +++ b/backend/src/core/api/cv/cv.resolver.js @@ -0,0 +1,33 @@ +import { Module } from 'packages/handler/Module'; +import { hashRole } from 'core/modules/auth/guard'; +import { CreateCVInterceptor, UpdateCVInterceptor } from 'core/modules/cv/interceptor'; +import { CVController } from './cv.controller'; + +export const CVResolver = Module.builder() + .addPrefix({ + prefixPath: '/cv', + tag: 'cv', + module: 'CVModule', + }) + .register([ + { + route: '/', + method: 'post', + body: 'CreateCVDto', + // guards: [hashRole], + interceptors: [CreateCVInterceptor], + controller: CVController.createOne, + }, + { + route: '/:id', + method: 'get', + controller: CVController.findById, + }, + { + route: '/:id', + method: 'put', + body: 'UpdateCVDto', + interceptors: [UpdateCVInterceptor], + controller: CVController.updateCV, + }, + ]); \ No newline at end of file diff --git a/backend/src/core/api/cv/index.js b/backend/src/core/api/cv/index.js new file mode 100644 index 0000000..f4a5fc6 --- /dev/null +++ b/backend/src/core/api/cv/index.js @@ -0,0 +1 @@ +export * from './cv.resolver'; \ No newline at end of file diff --git a/backend/src/core/api/index.js b/backend/src/core/api/index.js index 120332a..ac8603b 100644 --- a/backend/src/core/api/index.js +++ b/backend/src/core/api/index.js @@ -3,6 +3,7 @@ import { UserResolver } from 'core/api/user/user.resolver'; import { ApiDocument } from 'core/config/swagger.config'; import { HandlerResolver } from '../../packages/handler/HandlerResolver'; import { AuthResolver } from './auth/auth.resolver'; +import { CVResolver } from './cv/cv.resolver'; export const ModuleResolver = HandlerResolver .builder() @@ -10,5 +11,6 @@ export const ModuleResolver = HandlerResolver .addModule([ AuthResolver, UserResolver, - MediaResolver + MediaResolver , + CVResolver ]); diff --git a/backend/src/core/modules/auth/service/auth.service.js b/backend/src/core/modules/auth/service/auth.service.js index 819a79d..37443b2 100644 --- a/backend/src/core/modules/auth/service/auth.service.js +++ b/backend/src/core/modules/auth/service/auth.service.js @@ -4,7 +4,7 @@ import { UserDataService } from 'core/modules/user/services/userData.service'; import { joinUserRoles } from 'core/utils/userFilter'; import { BcryptService } from './bcrypt.service'; import { JwtService } from './jwt.service'; -import { UserRepository } from '../../user/user.repository'; +import { UserRepository } from '../../user/repository/user.repository'; import { UnAuthorizedException } from '../../../../packages/httpException'; class Service { diff --git a/backend/src/core/modules/cv/dto/createCV.dto.js b/backend/src/core/modules/cv/dto/createCV.dto.js new file mode 100644 index 0000000..e151b8c --- /dev/null +++ b/backend/src/core/modules/cv/dto/createCV.dto.js @@ -0,0 +1,75 @@ +import { ApiDocument } from 'core/config/swagger.config'; +import { SwaggerDocument } from 'packages/swagger'; + +ApiDocument.addModel('CreateCVDto', { + profileId: SwaggerDocument.ApiProperty({ type: 'string' }), + jobType: SwaggerDocument.ApiProperty({ type: 'string', required: false }), + workMode: SwaggerDocument.ApiProperty({ type: 'string', required: false }), + mobility: SwaggerDocument.ApiProperty({ type: 'string', required: false }), + expectedJob: SwaggerDocument.ApiProperty({ type: 'string', required: false }), + deviceIds: SwaggerDocument.ApiProperty({type: 'array', required: false,items: {type: 'string',},}), + skills: SwaggerDocument.ApiProperty({type: 'array', required: false, + items: { + type: 'object', required: ['name', 'type'], + properties: { + name: { + type: 'string', + }, + type: { + type: 'string', + enum: ['hard_skill', 'soft_skill'], + }, + }, + }, + }), + conditions: SwaggerDocument.ApiProperty({type: 'array', required: false,items: {type: 'string',},}), + experiences: SwaggerDocument.ApiProperty({type: 'array', required: false, + items: { + type: 'object', + properties: { + description: { + type: 'string', + }, + company: { + type: 'string', + }, + position: { + type: 'string', + }, + startDate: { + type: 'string', + }, + endDate: { + type: 'string', + }, + }, + }, + }), + certificates: SwaggerDocument.ApiProperty({type: 'array', required: false,items: {type: 'string',},}), + customSections: SwaggerDocument.ApiProperty({type: 'array', required: false, + items: { + type: 'object', + properties: { + title: { + type: 'string', + }, + content: { + type: 'string', + }, + }, + }, + }), +}); + +export const CreateCVDto = body => ({ + profile_id: body.profileId, + job_type: body.jobType || null, + work_mode: body.workMode || null, + mobility: body.mobility || null, + expected_job: body.expectedJob || null, + skills: body.skills ? JSON.stringify(body.skills) : null, + conditions: body.conditions ? JSON.stringify(body.conditions) : null, + experiences: body.experiences ? JSON.stringify(body.experiences) : null, + certificates: body.certificates ? JSON.stringify(body.certificates) : null, + custom_sections: body.customSections ? JSON.stringify(body.customSections) : null, +}); \ No newline at end of file diff --git a/backend/src/core/modules/cv/dto/index.js b/backend/src/core/modules/cv/dto/index.js new file mode 100644 index 0000000..229193c --- /dev/null +++ b/backend/src/core/modules/cv/dto/index.js @@ -0,0 +1,2 @@ +export * from './createCV.dto'; +export * from './updateCV.dto'; \ No newline at end of file diff --git a/backend/src/core/modules/cv/dto/updateCV.dto.js b/backend/src/core/modules/cv/dto/updateCV.dto.js new file mode 100644 index 0000000..252ecad --- /dev/null +++ b/backend/src/core/modules/cv/dto/updateCV.dto.js @@ -0,0 +1,77 @@ +import { ApiDocument } from 'core/config/swagger.config'; +import { SwaggerDocument } from 'packages/swagger'; + +ApiDocument.addModel('UpdateCVDto', { + profileId: SwaggerDocument.ApiProperty({ type: 'string' }), + jobType: SwaggerDocument.ApiProperty({ type: 'string', required: false }), + workMode: SwaggerDocument.ApiProperty({ type: 'string', required: false }), + mobility: SwaggerDocument.ApiProperty({ type: 'string', required: false }), + expectedJob: SwaggerDocument.ApiProperty({ type: 'string', required: false }), + deviceIds: SwaggerDocument.ApiProperty({type: 'array', required: false,items: {type: 'string',},}), + skills: SwaggerDocument.ApiProperty({type: 'array', required: false, + items: { + type: 'object', required: ['name', 'type'], + properties: { + name: { + type: 'string', + }, + type: { + type: 'string', + enum: ['hard_skill', 'soft_skill'], + }, + }, + }, + }), + conditions: SwaggerDocument.ApiProperty({type: 'array', required: false,items: {type: 'string',},}), + experiences: SwaggerDocument.ApiProperty({type: 'array', required: false, + items: { + type: 'object', + properties: { + description: { + type: 'string', + }, + company: { + type: 'string', + }, + position: { + type: 'string', + }, + startDate: { + type: 'string', + }, + endDate: { + type: 'string', + }, + }, + }, + }), + certificates: SwaggerDocument.ApiProperty({type: 'array', required: false,items: {type: 'string',},}), + customSections: SwaggerDocument.ApiProperty({type: 'array', required: false, + items: { + type: 'object', + properties: { + title: { + type: 'string', + }, + content: { + type: 'string', + }, + }, + }, + }), +}); +export const UpdateCVDto = body => { + const dto = {}; + + if (body.jobType !== undefined) dto.job_type = body.jobType; + if (body.workMode !== undefined) dto.work_mode = body.workMode; + if (body.mobility !== undefined) dto.mobility = body.mobility; + if (body.expectedJob !== undefined) dto.expected_job = body.expectedJob; + if (body.skills !== undefined) dto.skills = JSON.stringify(body.skills); + if (body.conditions !== undefined) dto.conditions = JSON.stringify(body.conditions); + if (body.experiences !== undefined) dto.experiences = JSON.stringify(body.experiences); + if (body.certificates !== undefined) dto.certificates = JSON.stringify(body.certificates); + if (body.customSections !== undefined) dto.custom_sections = JSON.stringify(body.customSections); + + return dto; +}; \ No newline at end of file diff --git a/backend/src/core/modules/cv/interceptor/create-cv.interceptor.js b/backend/src/core/modules/cv/interceptor/create-cv.interceptor.js new file mode 100644 index 0000000..27d0bc9 --- /dev/null +++ b/backend/src/core/modules/cv/interceptor/create-cv.interceptor.js @@ -0,0 +1,26 @@ +import Joi from 'joi'; +import { DefaultValidatorInterceptor } from 'core/infrastructure/interceptor'; +import { JoiUtils } from '../../../utils'; + +export const CreateCVInterceptor = new DefaultValidatorInterceptor( + Joi.object({ + profileId: JoiUtils.requiredString(), + jobType: JoiUtils.optionalString(), + workMode: JoiUtils.optionalString(), + mobility: JoiUtils.optionalString(), + expectedJob: JoiUtils.optionalString(), + skills: Joi.array() + .items( + Joi.object({ + name: Joi.string().required(), + type: Joi.string().valid('hard_skill', 'soft_skill').required(), + }) + ) + .optional(), + conditions: Joi.array().items(Joi.string()).optional(), + experiences:Joi.array().items(Joi.object()).optional(), + certificates: Joi.array().items(Joi.string()).optional(), + customSections: Joi.array().items(Joi.object()).optional(), + deviceIds: Joi.array().items(Joi.string().uuid()).optional(), + }).unknown(true) +); \ No newline at end of file diff --git a/backend/src/core/modules/cv/interceptor/index.js b/backend/src/core/modules/cv/interceptor/index.js new file mode 100644 index 0000000..2914202 --- /dev/null +++ b/backend/src/core/modules/cv/interceptor/index.js @@ -0,0 +1,2 @@ +export * from './create-cv.interceptor'; +export * from './update-cv.interceptor'; \ No newline at end of file diff --git a/backend/src/core/modules/cv/interceptor/update-cv.interceptor.js b/backend/src/core/modules/cv/interceptor/update-cv.interceptor.js new file mode 100644 index 0000000..dca96f2 --- /dev/null +++ b/backend/src/core/modules/cv/interceptor/update-cv.interceptor.js @@ -0,0 +1,26 @@ + import Joi from 'joi'; +import { DefaultValidatorInterceptor } from 'core/infrastructure/interceptor'; +import { JoiUtils } from '../../../utils'; + +export const UpdateCVInterceptor = new DefaultValidatorInterceptor( + Joi.object({ + profileId: JoiUtils.optionalString(), + jobType: JoiUtils.optionalString(), + workMode: JoiUtils.optionalString(), + summary: JoiUtils.optionalString(), + skills: Joi.array() + .items( + Joi.object({ + name: Joi.string().required(), + type: Joi.string().valid('hard_skill', 'soft_skill').required(), + }) + ) + .optional(), + experiences: Joi.array().items(Joi.object()).optional(), + educations: Joi.array().items(Joi.object()).optional(), + certifications: Joi.array().items(Joi.object()).optional(), + languages: Joi.array().items(Joi.string()).optional(), + avatar: JoiUtils.optionalString(), + status: JoiUtils.optionalString(), + }).unknown(true) +); \ No newline at end of file diff --git a/backend/src/core/modules/cv/repository/cv.repository.js b/backend/src/core/modules/cv/repository/cv.repository.js new file mode 100644 index 0000000..48130b2 --- /dev/null +++ b/backend/src/core/modules/cv/repository/cv.repository.js @@ -0,0 +1,60 @@ +import { DataRepository } from 'packages/restBuilder/core/dataHandler/data.repository'; + +class Repository extends DataRepository { + baseSelect() { + return [ + 'cvs.id', + 'cvs.profile_id as profileId', + 'cvs.job_type as jobType', + 'cvs.work_mode as workMode', + 'cvs.mobility', + 'cvs.expected_job as expectedJob', + 'cvs.skills', + 'cvs.conditions', + 'cvs.experiences', + 'cvs.certificates', + 'cvs.custom_sections as customSections', + 'cvs.created_at as createdAt', + 'cvs.updated_at as updatedAt', + ]; + } + + createCV(cvData) { + return this.query() + .insert(cvData) + .returning(this.baseSelect()); + } + + findById(id) { + return this.query() + .innerJoin('profiles', 'profiles.id', 'cvs.profile_id') + .innerJoin('users', 'users.id', 'profiles.user_id') + .where('cvs.id', id) + .whereNull('cvs.deleted_at') + .select([ + ...this.baseSelect(), + + 'profiles.full_name as fullName', + 'profiles.phone', + 'profiles.gender', + 'profiles.disability_status as disabilityStatus', + + 'users.email', + ]) + .first(); + } + + updateCV(id, cvData) { + return this.query() + .where('id', id) + .whereNull('deleted_at') + .update({ + ...cvData, + updated_at: new Date(), + }) + .returning(this.baseSelect()); + } + +} + +export const CVRepository = new Repository('cvs'); \ No newline at end of file diff --git a/backend/src/core/modules/cv/service/cv.service.js b/backend/src/core/modules/cv/service/cv.service.js new file mode 100644 index 0000000..bb7f20c --- /dev/null +++ b/backend/src/core/modules/cv/service/cv.service.js @@ -0,0 +1,63 @@ +import { CVRepository } from '../repository/cv.repository.js'; +import { getTransaction } from 'core/database'; +import { CreateCVDto , UpdateCVDto} from "../dto/index.js"; +import { UserDeviceRepository } from '../../user/repository/user_devices.repository.js'; +class Service { + constructor() { + this.repository = CVRepository; + } + + async createOne(cvData) { + + const trx = await getTransaction(); + try { + const cv = await this.repository.createCV(CreateCVDto(cvData),trx); + + if (cvData.deviceIds?.length) { + await UserDeviceRepository.createUserDevices(cvData.profileId,cvData.deviceIds,trx ); + } + + await trx.commit(); + return cv; + } catch (e) { + await trx.rollback(); + throw e; + } + } + + async getCvById(id) { + const cv = await this.repository.findById(id); + if (!cv) { + throw new Error('CV not found'); + } + return cv; + } + + async updateCV(id, cvData) { + const trx = await getTransaction(); + try { + // update cv + const updatedCV = await this.repository.updateCV(id,UpdateCVDto(cvData),trx); + + if (!updatedCV || updatedCV.length === 0) { + throw new Error('CV not found or update failed'); + } + // update devices + if (cvData.deviceIds !== undefined) { + await UserDeviceRepository.deleteByProfileId(cvData.profileId,trx); + + if (cvData.deviceIds.length) { + await UserDeviceRepository.createUserDevices(cvData.profileId,cvData.deviceIds,trx); + } + } + + await trx.commit(); + return updatedCV[0]; + + } catch (e) { + await trx.rollback(); + throw e; + } + } +} +export const CVService = new Service(); diff --git a/backend/src/core/modules/user/user.repository.js b/backend/src/core/modules/user/repository/user.repository.js similarity index 100% rename from backend/src/core/modules/user/user.repository.js rename to backend/src/core/modules/user/repository/user.repository.js diff --git a/backend/src/core/modules/user/repository/user_devices.repository.js b/backend/src/core/modules/user/repository/user_devices.repository.js new file mode 100644 index 0000000..e6f5ba2 --- /dev/null +++ b/backend/src/core/modules/user/repository/user_devices.repository.js @@ -0,0 +1,32 @@ +import { DataRepository } + from 'packages/restBuilder/core/dataHandler/data.repository'; + +class Repository extends DataRepository { + + createUserDevices(profile_id, device_ids = [], trx = null) { + if (!device_ids.length) { + return Promise.resolve([]); + } + const rows = device_ids.map(device_id => ({profile_id,device_id,})); + const queryBuilder = this.query().insert(rows); + if (trx) { + queryBuilder.transacting(trx); + } + return queryBuilder; + } + + deleteByProfileId(profile_id, trx = null) { + + const queryBuilder = this.query() + .where('profile_id', profile_id) + .delete(); + + if (trx) { + queryBuilder.transacting(trx); + } + + return queryBuilder; + } +} + +export const UserDeviceRepository = new Repository('user_devices'); \ No newline at end of file diff --git a/backend/src/core/modules/user/services/user.service.js b/backend/src/core/modules/user/services/user.service.js index 3ce46f0..1eab3ff 100644 --- a/backend/src/core/modules/user/services/user.service.js +++ b/backend/src/core/modules/user/services/user.service.js @@ -4,7 +4,7 @@ import { UserRoleRepository } from 'core/modules/role/userRole.repository'; import { joinUserRoles } from 'core/utils/userFilter'; import { Optional } from '../../../utils'; import { NotFoundException, DuplicateException, BadRequestException } from '../../../../packages/httpException'; -import { UserRepository } from '../user.repository'; +import { UserRepository } from '../repository/user.repository'; class Service { constructor() { diff --git a/backend/src/core/modules/user/services/user_devices.service.js b/backend/src/core/modules/user/services/user_devices.service.js new file mode 100644 index 0000000..d463409 --- /dev/null +++ b/backend/src/core/modules/user/services/user_devices.service.js @@ -0,0 +1,12 @@ +import { CVRepository } from '../repository/cv.repository.js'; +import { UserDeviceRepository } from '../repository/user-device.repository.js'; +import { CreateCVDto } from '../dto/create-cv.dto.js'; + +class Service { + constructor() { + this.repository = CVRepository; + } + +} + +export const CVService = new Service(); \ No newline at end of file diff --git a/backend/src/packages/swagger/core/document.js b/backend/src/packages/swagger/core/document.js index bdf0206..6097449 100644 --- a/backend/src/packages/swagger/core/document.js +++ b/backend/src/packages/swagger/core/document.js @@ -133,8 +133,9 @@ export class SwaggerDocument { name: pattern, in: 'path', schema: { - type: 'integer', - format: 'int64', + // type: 'integer', + // format: 'int64', + type: 'string' }, required: true, });