DevFeature/ Grit-metre - #7
Merged
Merged
Conversation
Updated dockerfile
Updated auth
Feature/grit metre
Feature/ Grit-metre
There was a problem hiding this comment.
Pull request overview
This PR refactors the existing scheduler feature into a JobsModule, adds a new “Grit Meter” module that performs daily DB-driven processing via cron, and introduces production-oriented configuration/deployment changes (MySQL config, API key guard, Docker, GitHub Actions deploy).
Changes:
- Reworked scheduler functionality into
src/modules/jobs/*(service/controller/module, runner sync logic, entity layout, DTO changes) and removed legacysrc/scheduler/*module + its e2e spec. - Added
GritMeterModulewith a daily cron task plus a manual trigger endpoint. - Added global API-key authentication and updated deployment/config assets (MySQL TypeORM async config, Docker/Docker Compose, production workflow, README/env examples).
Reviewed changes
Copilot reviewed 19 out of 23 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.json | Switches TS module/target settings and introduces path aliases. |
| src/scheduler/scheduler.module.ts | Removes legacy SchedulerModule. |
| src/scheduler/scheduler.controller.spec.ts | Removes legacy scheduler e2e spec coverage. |
| src/modules/jobs/jobs.service.ts | Renames SchedulerService to JobsService and keeps persistence/scheduling coordination. |
| src/modules/jobs/jobs.module.ts | Introduces JobsModule wiring (controller/providers/exports). |
| src/modules/jobs/jobs.controller.ts | Renames controller to JobsController and keeps /jobs routes. |
| src/modules/jobs/job-runner.service.ts | Adds periodic DB sync/rescheduling behavior and runner cleanups. |
| src/modules/jobs/entities/job.entity.ts | Adds JobEntity under the jobs module. |
| src/modules/jobs/dto/create-job.dto.ts | Simplifies job creation DTO, loosening scheduling validation. |
| src/modules/grit-meter/grit-meter.service.ts | Adds daily grit-meter cron processing and Discord webhook integration. |
| src/modules/grit-meter/grit-meter.module.ts | Adds grit-meter Nest module. |
| src/modules/grit-meter/grit-meter.controller.ts | Adds manual trigger endpoint for grit-meter processing. |
| src/common/guards/api-key.guard.ts | Adds API key authentication guard. |
| src/app.module.ts | Moves to ConfigModule + MySQL TypeORM async configuration and installs global guard; wires new modules. |
| README.md | Expands API documentation for jobs endpoints. |
| package.json | Adds @nestjs/config and mysql2 dependencies. |
| package-lock.json | Locks new dependencies. |
| Dockerfile | Adds multi-stage build for containerizing the service. |
| docker-compose.yml | Adds compose definition for running the service container. |
| .github/workflows/main.yml | Adds production deploy workflow via SSH. |
| .env.example | Adds environment variable template for DB/auth/Discord config. |
| .dockerignore | Adds ignore rules for Docker builds. |
Suppressed comments (3)
src/modules/jobs/job-runner.service.ts:23
parseIntcan produce NaN (or a very small value) for JOB_SYNC_INTERVAL_MS, andsetInterval(..., NaN)effectively becomes a 0ms interval in Node, which can cause a tight loop and DB/log spam. Validate the env var and fall back to a safe default/minimum.
src/modules/jobs/dto/create-job.dto.ts:6IsDateStringis no longer used after removing the scheduling DTOs; leaving it imported will typically fail linting (unused import) and adds noise.
src/modules/jobs/dto/create-job.dto.ts:68CreateJobDto.schedulingis now completely unvalidated (any). This allows creating jobs without required scheduling fields for their type (e.g. oneoff without execute_at / recurring without cron), which will be persisted asscheduledbut never actually scheduled by the runner (it only warns and returns). Consider reintroducing type-specific validation (or a custom validator) so invalid jobs are rejected at the API boundary.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+28
to
+34
| const apiKey = | ||
| this.configService.get<string>('SCHEDULER_SERVICE_API_KEY') || | ||
| this.configService.get<string>('API_KEY'); | ||
|
|
||
| if (token !== apiKey) { | ||
| throw new UnauthorizedException('Invalid API Key'); | ||
| } |
Comment on lines
+18
to
+36
| const dbEngine = config.get<string>('DATABASE_ENGINE') || config.get<string>('DB_TYPE') || 'mysql'; | ||
| const isMysql = dbEngine.includes('mysql') || dbEngine.includes('mariadb'); | ||
| const entities = [__dirname + '/**/*.entity{.ts,.js}']; | ||
|
|
||
| if (!isMysql) { | ||
| throw new Error(`Unsupported database engine "${dbEngine}". Please check DATABASE_ENGINE / DB_TYPE in .env`); | ||
| } | ||
|
|
||
| return { | ||
| type: 'mysql' as const, | ||
| host: config.get<string>('DATABASE_HOST', 'localhost'), | ||
| port: parseInt(config.get<string>('DATABASE_PORT', '3306'), 10), | ||
| username: config.get<string>('DATABASE_USER', 'root'), | ||
| password: config.get<string>('DATABASE_PASSWORD', ''), | ||
| database: config.get<string>('DATABASE_NAME', 'mulearn'), | ||
| entities, | ||
| synchronize: config.get<string>('DB_SYNC', 'false') === 'true', | ||
| logging: config.get<string>('DB_LOGGING', 'false') === 'true', | ||
| }; |
Comment on lines
+3
to
+5
| A robust job scheduling service that allows you to schedule HTTP requests to be executed either once or on a recurring schedule (cron). | ||
|
|
||
| ## API Endpoints |
Comment on lines
+14
to
+15
| - name: Checkout repository | ||
| uses: actions/checkout@v3 |
Comment on lines
+18
to
+21
| - name: Configure SSH key | ||
| uses: webfactory/ssh-agent@v0.4.1 | ||
| with: | ||
| ssh-private-key: ${{ secrets.PROD_SSH_PRIVATE_KEY }} |
Comment on lines
+27
to
+28
| run: | | ||
| ssh -o StrictHostKeyChecking=no ubuntu@$REMOTE_IP "cd $PROJECT_PATH && git pull && docker-compose up --build -d" |
| RUN npm ci | ||
|
|
||
| COPY . . | ||
| RUN npm run build |
Comment on lines
+73
to
+83
| for (const link of userLinks) { | ||
| const activityResult: Array<{ activity_count: number }> = await queryRunner.query( | ||
| ` | ||
| SELECT COUNT(*) AS activity_count | ||
| FROM karma_activity_log | ||
| WHERE user_id = ? | ||
| AND created_at >= DATE_SUB(CURDATE(), INTERVAL 1 DAY) | ||
| AND created_at < CURDATE() | ||
| `, | ||
| [link.user_id], | ||
| ); |
Comment on lines
+36
to
+43
| async processDailyGritMeter(): Promise<{ processed: number; levelDowns: number }> { | ||
| this.logger.log('Starting Daily Grit Meter / HP Processing'); | ||
|
|
||
| const isEnabled = await this.checkFeatureFlag(); | ||
| if (!isEnabled) { | ||
| this.logger.warn('Grit Meter processing skipped: Feature flag "grit_meter_enabled" is OFF'); | ||
| return { processed: 0, levelDowns: 0 }; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.