Skip to content

Fix alert delivery timeouts, search filter bugs, and forum anonymous authoring - #1185

Merged
RUKAYAT-CODER merged 2 commits into
rinafcode:mainfrom
sublime247:fix/alert-search-forum-issues
Jul 30, 2026
Merged

Fix alert delivery timeouts, search filter bugs, and forum anonymous authoring#1185
RUKAYAT-CODER merged 2 commits into
rinafcode:mainfrom
sublime247:fix/alert-search-forum-issues

Conversation

@sublime247

@sublime247 sublime247 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #994,
Closes #995,
Closes #997,
Closes #990.

  • Add timeouts and failure visibility to outbound alert delivery HTTP calls #994AlertingService and SlackService fired outbound Slack/PagerDuty HTTP calls with no timeout, and SlackService.sendAlert swallowed delivery failures in an empty catch with logging commented out. Adds ALERT_DELIVERY_TIMEOUT_MS to every outbound call, bounded jittered-backoff retry on transient 5xx responses, an alert_delivery_failures_total counter labelled by channel, and replaces the empty catch with Logger.error including the response status.
  • Fix broken category filter caused by missing spread operator in SearchService IN clause #995SearchService built the category filter with course.category IN (:cats) instead of the spread form IN (:...cats), so TypeORM bound the array as a single scalar parameter and category filtering silently broke (masked by the surrounding catch). Fixes the spread form and implements the level/language filters declared in SearchFilters but never wired up — they weren't backed by any column, so a migration adds them to course (nullable, indexed, mirroring category).
  • Stop masking search failures as empty result sets in SearchService #997SearchService.search()/getAutoComplete() caught any error — including infrastructure failures — and returned an empty result set with a 200, making outages indistinguishable from a genuine zero-result search. Now rethrows: infrastructure errors become a 503 (ServiceUnavailableException), malformed filter values (Postgres 22xxx data-exception SQLSTATE) become a 400, and both increment search_query_failures_total labelled by failure class. The existing ES→DB fallback path (and its counter) is untouched.
  • Stop attributing forum posts and votes to a shared 'anonymous' author identifier #990ForumController computed authorId = req.user?.id || 'anonymous' with no guard on any write handler, so every write was attributed to a shared 'anonymous' identity, and ForumService.vote's lookup by (entityType, entityId, authorId) meant every anonymous voter collided on one row — vote tallies were meaningless. Adds JwtAuthGuard to the write handlers (reads stay public), removes the fallback, and adds a migration that purges/flags pre-existing anonymous rows, recomputes affected vote tallies, and adds a foreign key from forum_votes.authorId to users.id.

Test plan

  • npx tsc --noEmit clean on all touched files
  • npx eslint clean on all touched files
  • Unit tests (mocked axios/query-builder) added/updated and passing:
    • src/monitoring/alerting/alerting.service.spec.ts — timeout, retry/backoff, failure counter
    • src/slack.service.spec.ts — timeout, retry, no-more-empty-catch, failure counter
    • src/search/search.service.spec.ts — spread-form SQL/param assertions (single + multi value), 503/400 classification, failure counter
    • src/forum/forum.controller.spec.ts — real HTTP + real JwtAuthGuard (not mocked) proving anonymous writes get 401 and authenticated writes use the real user id, never 'anonymous'
  • src/search/search.service.category-filter.integration.spec.ts — exercises the real TypeORM query builder against Postgres (not mocked), seeding courses across two categories; verified it fails against the original unfixed IN (:cats) form and passes against the fix. Excluded from the default npm test run like other *.integration.spec.ts files in this repo — run explicitly against a live database.
  • Migration SQL hand-validated against throwaway Postgres tables (purge → tally recompute → flag → type conversion → FK

…authoring

Addresses four issues:

rinafcode#994 - AlertingService and SlackService fired outbound HTTP calls with no
timeout and no bounded retry, and SlackService.sendAlert swallowed delivery
failures in an empty catch with logging commented out. Adds
ALERT_DELIVERY_TIMEOUT_MS to every outbound call, bounded jittered-backoff
retry on transient 5xx, an alert_delivery_failures_total counter labelled by
channel, and replaces the empty catch with a proper Logger.error call.

rinafcode#995 - SearchService built the category filter with
`course.category IN (:cats)` instead of the spread form
`IN (:...cats)`, so TypeORM bound the array as a single scalar parameter
and category filtering silently broke. Fixes the spread form and implements
the level/language filters declared in SearchFilters but never wired up
(added as new nullable/indexed columns on Course via migration, since they
didn't exist).

rinafcode#997 - SearchService.search()/getAutoComplete() caught any error - including
infrastructure failures - and returned an empty result set with a 200,
making outages indistinguishable from a genuine zero-result search. Now
rethrows: infrastructure errors become a 503 (ServiceUnavailableException),
malformed filter values (Postgres 22xxx data-exception SQLSTATE) become a
400, and both increment search_query_failures_total labelled by failure
class.

rinafcode#990 - ForumController computed `authorId = req.user?.id || 'anonymous'`
with no guard, so every write was attributed to a shared 'anonymous'
identity and ForumService.vote's collision on that id made vote tallies
meaningless. Adds JwtAuthGuard to write handlers, removes the fallback, adds
a migration purging/flagging pre-existing anonymous rows and adding a
foreign key from forum_votes.authorId to users.id.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@RUKAYAT-CODER

Copy link
Copy Markdown
Contributor

Kindly resolve conflict.
Your PR is not properly linked, only linked to one issue

@drips-wave

drips-wave Bot commented Jul 30, 2026

Copy link
Copy Markdown

@sublime247 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@RUKAYAT-CODER

Copy link
Copy Markdown
Contributor

Thank you for contributing to the project.

@RUKAYAT-CODER
RUKAYAT-CODER merged commit a5c981e into rinafcode:main Jul 30, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants