From ce89d633a94bcac0c83bdfd3b18c219b736dbbf8 Mon Sep 17 00:00:00 2001 From: Mftee <113613891+mftee@users.noreply.github.com> Date: Fri, 29 May 2026 19:55:25 +0100 Subject: [PATCH 01/11] feat: add reporting-service package.json --- microservices/reporting-service/package.json | 51 ++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 microservices/reporting-service/package.json diff --git a/microservices/reporting-service/package.json b/microservices/reporting-service/package.json new file mode 100644 index 0000000..5e5885c --- /dev/null +++ b/microservices/reporting-service/package.json @@ -0,0 +1,51 @@ +{ + "name": "reporting-service", + "version": "0.0.1", + "description": "Analytics reporting service for custom reports and business intelligence", + "author": "", + "private": true, + "license": "UNLICENSED", + "scripts": { + "build": "nest build", + "start": "nest start", + "start:dev": "nest start --watch", + "start:prod": "node dist/main", + "lint": "eslint \"{src,test}/**/*.ts\" --fix", + "type-check": "tsc --noEmit", + "test": "jest", + "test:cov": "jest --coverage" + }, + "dependencies": { + "@nestjs/common": "^10.4.4", + "@nestjs/config": "^3.2.3", + "@nestjs/core": "^10.4.4", + "@nestjs/platform-express": "^10.4.4", + "@nestjs/typeorm": "^11.0.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.1", + "pg": "^8.13.1", + "reflect-metadata": "^0.2.2", + "rxjs": "^7.8.1", + "typeorm": "^0.3.20" + }, + "devDependencies": { + "@nestjs/cli": "^10.4.5", + "@nestjs/schematics": "^10.1.4", + "@nestjs/testing": "^10.4.4", + "@types/jest": "^29.5.12", + "@types/node": "^20.14.15", + "jest": "^29.7.0", + "ts-jest": "^29.2.4", + "ts-node": "^10.9.2", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.5.4" + }, + "jest": { + "moduleFileExtensions": ["js", "json", "ts"], + "rootDir": "src", + "testRegex": ".*\\.spec\\.ts$", + "transform": { "^.+\\.(t|j)s$": "ts-jest" }, + "coverageDirectory": "../coverage", + "testEnvironment": "node" + } +} \ No newline at end of file From cbe4f08e768c944fd69ce0d078e88ec86ccb32e6 Mon Sep 17 00:00:00 2001 From: Mftee <113613891+mftee@users.noreply.github.com> Date: Fri, 29 May 2026 19:55:27 +0100 Subject: [PATCH 02/11] feat: add nest-cli.json --- microservices/reporting-service/nest-cli.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 microservices/reporting-service/nest-cli.json diff --git a/microservices/reporting-service/nest-cli.json b/microservices/reporting-service/nest-cli.json new file mode 100644 index 0000000..78a9ae6 --- /dev/null +++ b/microservices/reporting-service/nest-cli.json @@ -0,0 +1 @@ +{"$schema":"https://json.schemastore.org/nest-cli","collection":"@nestjs/schematics","sourceRoot":"src"} \ No newline at end of file From e7bf50e0add294c50e730e28e6f08f021086a0ec Mon Sep 17 00:00:00 2001 From: Mftee <113613891+mftee@users.noreply.github.com> Date: Fri, 29 May 2026 19:55:30 +0100 Subject: [PATCH 03/11] feat: add tsconfig.json --- microservices/reporting-service/tsconfig.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 microservices/reporting-service/tsconfig.json diff --git a/microservices/reporting-service/tsconfig.json b/microservices/reporting-service/tsconfig.json new file mode 100644 index 0000000..01bed67 --- /dev/null +++ b/microservices/reporting-service/tsconfig.json @@ -0,0 +1 @@ +{"compilerOptions":{"module":"commonjs","declaration":true,"removeComments":true,"emitDecoratorMetadata":true,"experimentalDecorators":true,"allowSyntheticDefaultImports":true,"target":"ES2021","sourceMap":true,"outDir":"./dist","baseUrl":"./","incremental":true,"skipLibCheck":true,"strictNullChecks":false,"noImplicitAny":false}} \ No newline at end of file From b5adc07a7bf33cec0b0c3b48ea5f75533e646307 Mon Sep 17 00:00:00 2001 From: Mftee <113613891+mftee@users.noreply.github.com> Date: Fri, 29 May 2026 19:55:33 +0100 Subject: [PATCH 04/11] feat: add tsconfig.build.json --- microservices/reporting-service/tsconfig.build.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 microservices/reporting-service/tsconfig.build.json diff --git a/microservices/reporting-service/tsconfig.build.json b/microservices/reporting-service/tsconfig.build.json new file mode 100644 index 0000000..2e00cfb --- /dev/null +++ b/microservices/reporting-service/tsconfig.build.json @@ -0,0 +1 @@ +{"extends":"./tsconfig.json","exclude":["node_modules","test","dist","**/*spec.ts"]} \ No newline at end of file From fbe2360751a67b70f66676ddb9d1e40aa4e584f8 Mon Sep 17 00:00:00 2001 From: Mftee <113613891+mftee@users.noreply.github.com> Date: Fri, 29 May 2026 19:55:36 +0100 Subject: [PATCH 05/11] feat: add Report entity --- .../reporting-service/src/report.entity.ts | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 microservices/reporting-service/src/report.entity.ts diff --git a/microservices/reporting-service/src/report.entity.ts b/microservices/reporting-service/src/report.entity.ts new file mode 100644 index 0000000..751d397 --- /dev/null +++ b/microservices/reporting-service/src/report.entity.ts @@ -0,0 +1,31 @@ +import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn } from 'typeorm'; + +export enum ReportFormat { + CSV = 'csv', + PDF = 'pdf', + JSON = 'json', +} + +@Entity('reports') +export class Report { + @PrimaryGeneratedColumn('uuid') + id: string; + + @Column() + name: string; + + @Column({ nullable: true }) + description: string; + + @Column({ type: 'jsonb', default: {} }) + query: Record; + + @Column({ type: 'enum', enum: ReportFormat, default: ReportFormat.JSON }) + format: ReportFormat; + + @Column({ nullable: true }) + scheduledCron: string; + + @CreateDateColumn() + createdAt: Date; +} \ No newline at end of file From cc6831dd2c89e713722f6df811747d0ca978ad5f Mon Sep 17 00:00:00 2001 From: Mftee <113613891+mftee@users.noreply.github.com> Date: Fri, 29 May 2026 19:55:38 +0100 Subject: [PATCH 06/11] feat: add ReportService --- .../reporting-service/src/report.service.ts | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 microservices/reporting-service/src/report.service.ts diff --git a/microservices/reporting-service/src/report.service.ts b/microservices/reporting-service/src/report.service.ts new file mode 100644 index 0000000..b878c71 --- /dev/null +++ b/microservices/reporting-service/src/report.service.ts @@ -0,0 +1,31 @@ +import { Injectable } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; +import { Report, ReportFormat } from './report.entity'; + +@Injectable() +export class ReportService { + constructor( + @InjectRepository(Report) + private readonly reportRepo: Repository, + ) {} + + create(data: Partial): Promise { + return this.reportRepo.save(this.reportRepo.create(data)); + } + + findAll(): Promise { + return this.reportRepo.find(); + } + + findOne(id: string): Promise { + return this.reportRepo.findOneBy({ id }); + } + + async export(id: string, format: ReportFormat): Promise<{ data: string; format: ReportFormat }> { + const report = await this.reportRepo.findOneBy({ id }); + if (!report) throw new Error(`Report ${id} not found`); + // Stub: real implementation would execute report.query and format output + return { data: JSON.stringify({ reportId: id, query: report.query }), format }; + } +} \ No newline at end of file From 09245c7c0ca63162eff66a4d76f2964d795b2818 Mon Sep 17 00:00:00 2001 From: Mftee <113613891+mftee@users.noreply.github.com> Date: Fri, 29 May 2026 19:55:40 +0100 Subject: [PATCH 07/11] feat: add ReportController --- .../src/report.controller.ts | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 microservices/reporting-service/src/report.controller.ts diff --git a/microservices/reporting-service/src/report.controller.ts b/microservices/reporting-service/src/report.controller.ts new file mode 100644 index 0000000..f0f3bf4 --- /dev/null +++ b/microservices/reporting-service/src/report.controller.ts @@ -0,0 +1,31 @@ +import { Controller, Get, Post, Param, Body, Query } from '@nestjs/common'; +import { ReportService } from './report.service'; +import { Report, ReportFormat } from './report.entity'; + +@Controller('reports') +export class ReportController { + constructor(private readonly reportService: ReportService) {} + + @Post() + create(@Body() body: Partial): Promise { + return this.reportService.create(body); + } + + @Get() + findAll(): Promise { + return this.reportService.findAll(); + } + + @Get(':id') + findOne(@Param('id') id: string): Promise { + return this.reportService.findOne(id); + } + + @Get(':id/export') + export( + @Param('id') id: string, + @Query('format') format: ReportFormat = ReportFormat.JSON, + ) { + return this.reportService.export(id, format); + } +} \ No newline at end of file From ec75d5a313ac4212737925dab2e916f827d37059 Mon Sep 17 00:00:00 2001 From: Mftee <113613891+mftee@users.noreply.github.com> Date: Fri, 29 May 2026 19:55:43 +0100 Subject: [PATCH 08/11] feat: add AppModule --- .../reporting-service/src/app.module.ts | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 microservices/reporting-service/src/app.module.ts diff --git a/microservices/reporting-service/src/app.module.ts b/microservices/reporting-service/src/app.module.ts new file mode 100644 index 0000000..84fbbe1 --- /dev/null +++ b/microservices/reporting-service/src/app.module.ts @@ -0,0 +1,26 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule, ConfigService } from '@nestjs/config'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { Report } from './report.entity'; +import { ReportService } from './report.service'; +import { ReportController } from './report.controller'; + +@Module({ + imports: [ + ConfigModule.forRoot({ isGlobal: true }), + TypeOrmModule.forRootAsync({ + imports: [ConfigModule], + useFactory: (config: ConfigService) => ({ + type: 'postgres', + url: config.get('DATABASE_URL'), + entities: [Report], + synchronize: true, + }), + inject: [ConfigService], + }), + TypeOrmModule.forFeature([Report]), + ], + controllers: [ReportController], + providers: [ReportService], +}) +export class AppModule {} \ No newline at end of file From 34452566305d03ea430f6df05286be74ff4e409d Mon Sep 17 00:00:00 2001 From: Mftee <113613891+mftee@users.noreply.github.com> Date: Fri, 29 May 2026 19:55:46 +0100 Subject: [PATCH 09/11] feat: add main.ts --- microservices/reporting-service/src/main.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 microservices/reporting-service/src/main.ts diff --git a/microservices/reporting-service/src/main.ts b/microservices/reporting-service/src/main.ts new file mode 100644 index 0000000..a31514e --- /dev/null +++ b/microservices/reporting-service/src/main.ts @@ -0,0 +1,11 @@ +import { NestFactory } from '@nestjs/core'; +import { AppModule } from './app.module'; + +async function bootstrap() { + const app = await NestFactory.create(AppModule); + app.enableCors(); + const port = process.env.PORT || 3013; + await app.listen(port, '0.0.0.0'); + console.log(`Reporting Service running on port ${port}`); +} +bootstrap(); \ No newline at end of file From 100e72315b456453c526919f9bb5a2cf98c14d3c Mon Sep 17 00:00:00 2001 From: Mftee <113613891+mftee@users.noreply.github.com> Date: Fri, 29 May 2026 19:55:48 +0100 Subject: [PATCH 10/11] feat: add ReportService unit tests --- .../src/report.service.spec.ts | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 microservices/reporting-service/src/report.service.spec.ts diff --git a/microservices/reporting-service/src/report.service.spec.ts b/microservices/reporting-service/src/report.service.spec.ts new file mode 100644 index 0000000..db46403 --- /dev/null +++ b/microservices/reporting-service/src/report.service.spec.ts @@ -0,0 +1,34 @@ +import { Test } from '@nestjs/testing'; +import { getRepositoryToken } from '@nestjs/typeorm'; +import { ReportService } from './report.service'; +import { Report, ReportFormat } from './report.entity'; + +describe('ReportService', () => { + let service: ReportService; + const mockRepo = { + create: jest.fn((d) => d), + save: jest.fn((d) => Promise.resolve({ id: 'uuid', ...d })), + find: jest.fn(() => Promise.resolve([])), + findOneBy: jest.fn(() => Promise.resolve({ id: 'uuid', name: 'test', query: {}, format: ReportFormat.JSON })), + }; + + beforeEach(async () => { + const module = await Test.createTestingModule({ + providers: [ + ReportService, + { provide: getRepositoryToken(Report), useValue: mockRepo }, + ], + }).compile(); + service = module.get(ReportService); + }); + + it('creates a report', async () => { + const result = await service.create({ name: 'Monthly Report' }); + expect(result).toBeDefined(); + }); + + it('exports a report as JSON', async () => { + const result = await service.export('uuid', ReportFormat.JSON); + expect(result.format).toBe(ReportFormat.JSON); + }); +}); \ No newline at end of file From ed7e3cf4da5a86ba8dfc9e31053e383313203e3f Mon Sep 17 00:00:00 2001 From: Mftee <113613891+mftee@users.noreply.github.com> Date: Fri, 29 May 2026 19:55:51 +0100 Subject: [PATCH 11/11] feat: add Dockerfile --- microservices/reporting-service/Dockerfile | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 microservices/reporting-service/Dockerfile diff --git a/microservices/reporting-service/Dockerfile b/microservices/reporting-service/Dockerfile new file mode 100644 index 0000000..2c0b1ca --- /dev/null +++ b/microservices/reporting-service/Dockerfile @@ -0,0 +1,6 @@ +FROM node:20-alpine +WORKDIR /app +COPY package*.json ./ +RUN npm ci --only=production +COPY dist ./dist +CMD ["node", "dist/main"] \ No newline at end of file