Skip to content

fix: production Docker build, health endpoint, and bug fixes#59

Open
ZiyadKakhandkikar wants to merge 3 commits into
voice-agentfrom
fix/docker-production-setup
Open

fix: production Docker build, health endpoint, and bug fixes#59
ZiyadKakhandkikar wants to merge 3 commits into
voice-agentfrom
fix/docker-production-setup

Conversation

@ZiyadKakhandkikar

Copy link
Copy Markdown
Collaborator

Summary

Fixes found while integrating this service into the Voice Note Analysis platform's docker-compose stack:

  • Dockerfile ran in dev mode. It used npm start (nest start), which is a dev-mode watcher, not a compiled production build. Switched to a two-stage build: stage 1 installs deps and runs npm run build to produce dist/, stage 2 is a slim runtime image that only installs prod deps and runs the compiled dist/src/main.js with node.
  • No /health endpoint. Docker/K8s healthchecks had nothing to hit and would mark the container permanently unhealthy. Added GET /health returning { status: "ok" } on AppController, plus a unit test.
  • Debug log with a developer's name. Removed a leftover console.log(result.value, "Shubham") in notification.service.ts.
  • Missing return in updatePermission. The catch block in role-permission-mapping.service.ts built an error response via APIResponse.error(...) but never returned it, so a failed /role-permission/update request would hang without ever sending a response. Added the missing return.
  • No .dockerignore. The build context was pulling in node_modules (200MB+), dist, coverage, and other local-only files. Added one.

Test plan

  • npm run build succeeds and produces dist/src/main.js.
  • npm test (app.controller.spec.ts) passes, including the new health check test.
  • docker build . succeeds end-to-end with the new multi-stage Dockerfile.
  • Ran the built image locally: it boots, initializes all Nest modules, and only fails on the expected ECONNREFUSED for RabbitMQ/Postgres since none are running in the sandbox — confirming the compiled entrypoint (dist/src/main) is correct.

- Dockerfile now compiles TypeScript in a build stage and runs the
  compiled dist/src/main output in a slim production image, instead of
  running `npm start` (nest start, dev mode) inside the container.
- Add GET /health so the Docker healthcheck has something to hit;
  previously there was no health route and the container was always
  marked unhealthy.
- Remove a leftover debug console.log that printed a developer's name.
- Fix updatePermission swallowing errors: the catch block built an
  error response but never returned it, so a failed update request
  would hang instead of getting a response.
- Add .dockerignore so the build context skips node_modules, dist,
  coverage, and other local-only files.

Co-authored-by: multica-agent <github@multica.ai>
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c4f71516-957b-4eb7-bbda-a4e24d659d5e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/docker-production-setup

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces several improvements, including a multi-stage Dockerfile build to optimize image size, the addition of a .dockerignore file, a new /health endpoint with associated unit tests, the removal of a debug log in the notification service, and a fix to return the error response in the role-permission mapping service. There are no review comments, and we have no additional feedback to provide.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

POST /notification-templates only ever wrote email/push/sms config rows —
there was no way to create a NotificationActionTemplates row with type='inApp'.
Since in-app sends resolve their content by looking up a published template with
type='inApp' for the action (InAppService.resolveContent), every context+key send
through POST /notification/send with an inApp block was guaranteed to fail with
"In-app template not found or not published for resolved action".

Adds an InAppNotificationDto (subject + body, same shape as the email DTO) to both
CreateEventDto and UpdateEventDto, and wires it into createTemplate/
updateNotificationTemplate the same way email/push/sms already are. No entity/migration
change needed — NotificationActionTemplates.type is a plain string column.

Found while integrating this service into an external platform that needs email +
in-app notifications from a single template.

Co-authored-by: multica-agent <github@multica.ai>
@ZiyadKakhandkikar

Copy link
Copy Markdown
Collaborator Author

Follow-up commit: added inApp support to POST /notification-templates (and update).

While seeding templates for the integration, discovered POST /notification-templates only ever created email/push/sms config rows — there was no way to create a type='inApp' row. Since in-app sends resolve content by looking up a published template with type='inApp' for the action, every POST /notification/send call with an inApp block and a context+key was guaranteed to fail with "In-app template not found or not published for resolved action".

Added an InAppNotificationDto (subject + body) to CreateEventDto/UpdateEventDto and wired it into the service the same way email/push/sms already are. No entity/migration change needed — NotificationActionTemplates.type is a plain string column.

Comment thread Dockerfile
COPY . .
RUN npm run build

FROM node:20-slim AS production
Found while standing up the service end-to-end for an external integration —
none of this surfaced before because local dev always ran against an
already-synced database.

- data-source.ts's migrations/entities globs were hardcoded to the .ts source
  paths ('src/migrations/*.ts'). That works when run via ts-node
  (npm run migration:*) but resolves to nothing when data-source.ts is
  compiled to dist/data-source.js for production (nest build emits
  dist/src/migrations/*.js, one directory deeper). migration:run against the
  compiled file silently reported "No migrations are pending" — the tables
  never got created. Switched to path.join(__dirname, 'src/migrations/*.{ts,js}'),
  which resolves correctly in both the ts-node and compiled cases since
  __dirname tracks whichever one is actually running.
- Since synchronize is false, migrations are the only thing that creates the
  schema — nothing was running them on container start. Dockerfile now runs
  `typeorm migration:run -d dist/data-source.js` before starting the app.
- CreateInAppNotification1764892800000 had a trailing comma before the
  closing paren in its CREATE TABLE statement (left over from a removed
  comment line) — invalid SQL, migration would fail as soon as it could
  actually run.
- BackfillCoreTables1765200000000 created 4 uuid primary key columns
  (NotificationActionTemplates.templateId, NotificationQueue.id,
  RolePermission.rolePermissionId, notificationLogs.id) with no DEFAULT.
  All 4 entities use @PrimaryGeneratedColumn('uuid') with no @BeforeInsert
  hook, so they rely entirely on a DB-level default — every insert into any
  of these tables (including creating a notification template) failed with
  a NOT NULL violation on the primary key. Added DEFAULT uuid_generate_v4()
  to each (the extension is already created automatically by TypeORM's
  postgres driver on connect).

Verified: dropped the notifications DB, rebuilt the image, confirmed
migrations run automatically on a fresh container and all 8 tables + their
UUID defaults come up correctly.

Co-authored-by: multica-agent <github@multica.ai>
@ZiyadKakhandkikar

Copy link
Copy Markdown
Collaborator Author

Follow-up commit: migrations never actually ran in production, and one had invalid SQL.

While standing this service up end-to-end (postgres + rabbitmq + the compiled Docker image) I found the schema was never getting created:

  • data-source.ts's migrations/entities globs were hardcoded to the .ts source paths. That's fine under npm run migration:* (ts-node), but nest build compiles migrations one directory deeper (dist/src/migrations/*.js), so running migration:run against the compiled dist/data-source.js matched nothing and silently said "No migrations are pending" — meaning no tables ever got created on a fresh deploy. Fixed with path.join(__dirname, 'src/migrations/*.{ts,js}'), which resolves correctly whichever way the file is loaded.
  • Since synchronize: false, migrations are the only thing that creates the schema, and nothing was running them on container start — added typeorm migration:run -d dist/data-source.js to the Dockerfile CMD before starting the app.
  • CreateInAppNotification1764892800000 had a trailing comma before the closing paren in its CREATE TABLE (leftover from a removed comment) — invalid SQL, would fail as soon as it could actually run.
  • BackfillCoreTables1765200000000 created 4 uuid primary keys with no DEFAULT (NotificationActionTemplates.templateId, NotificationQueue.id, RolePermission.rolePermissionId, notificationLogs.id). All 4 entities use @PrimaryGeneratedColumn('uuid') with no @BeforeInsert hook, so every insert — including creating a notification template — failed with a NOT NULL violation on the primary key. Added DEFAULT uuid_generate_v4() to each.

Verified by dropping the notifications DB, rebuilding, and confirming a fresh container creates all 8 tables (with working UUID defaults) automatically on start, then seeding templates and sending a real notification through /notification/send successfully.

@sonarqubecloud

sonarqubecloud Bot commented Jul 9, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
9.9% Duplication on New Code (required ≤ 3%)
B Security Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants