feat: implement webhook and event emitter#3
Conversation
…nfiguration for Discord bot
…sses and action handlers
There was a problem hiding this comment.
Pull request overview
This PR refactors the app to route GitHub/DB/LLM interactions through explicit integration modules, adds a lightweight event bus (with analytics consumer wiring), and introduces an Express endpoint to receive GitHub webhooks.
Changes:
- Introduces integrations for GitHub, DB (SQLite), and LLM providers (Gemini/OpenAI), and migrates bot orchestration to use them.
- Adds a new in-process event bus and an analytics consumer (console-backed).
- Adds GitHub webhook endpoints to the API server and adds Discord assignment notification behavior.
Reviewed changes
Copilot reviewed 85 out of 94 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.json | Minor tsconfig comment change. |
| src/utils/logger.ts | Updates config import path. |
| src/utils/index.ts | Re-exports logger via utils barrel. |
| src/main.bot.ts | Wires integrations + analytics + starts bot. |
| src/main.api.ts | Updates config import path for API entrypoint. |
| src/interfaces/bot/services/assignment-notification.service.ts | Adds Discord channel notification helper for assignments. |
| src/interfaces/bot/runtime-config.ts | Adds simple runtime config storage for standup channel ID. |
| src/interfaces/bot/handlers/message-create.handler.ts | Updates logger import + handler filename conventions. |
| src/interfaces/bot/handlers/llm-command.handler.ts | Switches from usecases to orchestrations; adds assignment notifications. |
| src/interfaces/bot/handlers/interaction-create.handler.ts | Updates logger import. |
| src/interfaces/bot/handlers/index.ts | Renames handler imports; registers Discord event handlers. |
| src/interfaces/bot/handlers/guild-create.handler.ts | Updates logger import path. |
| src/interfaces/bot/handlers/client-ready.handler.ts | Updates logger import path. |
| src/interfaces/bot/commands/unlink-github.command.ts | Switches to orchestrations; tweaks reply message. |
| src/interfaces/bot/commands/status.command.ts | Switches to orchestrations; updates Issue typing import. |
| src/interfaces/bot/commands/link-github.command.ts | Switches to orchestrations. |
| src/interfaces/bot/commands/index.ts | Updates command module filenames to kebab-case. |
| src/interfaces/bot/commands/create-issue.command.ts | Switches to orchestrations; updates logger import. |
| src/interfaces/bot/commands/assign-issue.command.ts | Adds ephemeral reply + assignment notifications; switches to orchestrations. |
| src/interfaces/bot/commands/add-repository.command.ts | Switches to orchestrations. |
| src/interfaces/bot/client.ts | Adds runtime config + DB connect (currently duplicated) before bot start. |
| src/interfaces/api/client.ts | Adds JSON API responses + GitHub webhook endpoints with logging. |
| src/integrations/llm/providers/openai/openai.provider.ts | Adds OpenAI provider adapter. |
| src/integrations/llm/providers/gemini/gemini.provider.ts | Adds Gemini provider adapter. |
| src/integrations/llm/prompts/index.ts | Exports prompt(s) for LLM integration. |
| src/integrations/llm/prompts/gitbot.prompt.ts | Renames system prompt constant for GitBot usage. |
| src/integrations/llm/prompts/assistant.prompt.ts | Adds a generic assistant prompt. |
| src/integrations/llm/llm.types.ts | Defines LLMProvider interface. |
| src/integrations/llm/llm.integration.ts | Adds LLM integration selecting provider + executing actions. |
| src/integrations/llm/index.ts | Exports singleton llmIntegration. |
| src/integrations/integration.interface.ts | Adds common integration interface. |
| src/integrations/github/repository/repository.types.ts | Adds payload typing for repo listing. |
| src/integrations/github/repository/index.ts | Exports repository actions/types. |
| src/integrations/github/repository/actions/get-repositories.action.ts | Adds Octokit action to list repos for a user. |
| src/integrations/github/issue/issue.types.ts | Adds payload typings for issue actions. |
| src/integrations/github/issue/index.ts | Exports issue actions/types. |
| src/integrations/github/issue/actions/get-issues.action.ts | Adds Octokit action to list repo issues. |
| src/integrations/github/issue/actions/create-issue.action.ts | Adds Octokit action to create an issue. |
| src/integrations/github/issue/actions/assign-issue.action.ts | Adds Octokit action to assign users to an issue. |
| src/integrations/github/index.ts | Exports singleton githubIntegration. |
| src/integrations/github/github.types.ts | Defines GitHub action names + payload map type(s). |
| src/integrations/github/github.integration.ts | Adds GitHub integration wrapper around action dispatch. |
| src/integrations/github/github.client.ts | Wraps Octokit client creation. |
| src/integrations/db/user-mappings/user-mappings.types.ts | Adds DB user mapping row/payload types. |
| src/integrations/db/user-mappings/index.ts | Exports user-mapping DB actions/types. |
| src/integrations/db/user-mappings/actions/set-user-mapping.action.ts | Adds upsert for user mappings. |
| src/integrations/db/user-mappings/actions/get-user-mapping.action.ts | Adds lookup for user mappings. |
| src/integrations/db/user-mappings/actions/delete-user-mapping.action.ts | Adds delete for user mappings. |
| src/integrations/db/index.ts | Exports DB integration surface. |
| src/integrations/db/guild-repositories/index.ts | Exports guild-repository DB actions/types. |
| src/integrations/db/guild-repositories/guild-repositories.types.ts | Adds DB guild repo row/payload types. |
| src/integrations/db/guild-repositories/actions/remove-guild-repository.action.ts | Adds delete for guild repositories. |
| src/integrations/db/guild-repositories/actions/get-guild-repositories.action.ts | Adds list for guild repositories. |
| src/integrations/db/guild-repositories/actions/add-guild-repository.action.ts | Adds insert for guild repositories. |
| src/integrations/db/db.types.ts | Adds DB action union type. |
| src/integrations/db/db.integration.ts | Adds DB integration wrapper and singleton export. |
| src/integrations/db/db.client.ts | Adds SQLite client wrapper + schema initialization. |
| src/integrations/analytics/providers/index.ts | Exports analytics providers. |
| src/integrations/analytics/providers/console.provider.ts | Adds console analytics provider. |
| src/integrations/analytics/index.ts | Adds analytics service + event consumer registration. |
| src/integrations/analytics/analytics.types.ts | Adds analytics provider interface. |
| src/integrations/analytics/analytics.services.ts | Adds fire-and-forget analytics tracking wrapper. |
| src/infrastructure/llm/index.ts | Removes legacy LLM export. |
| src/infrastructure/llm/client.ts | Removes legacy Gemini client wiring. |
| src/infrastructure/github/services/issue.service.ts | Removes legacy GitHub issue service. |
| src/infrastructure/github/services/index.ts | Removes legacy GitHub services barrel. |
| src/infrastructure/github/client.ts | Removes legacy GitHub client wiring. |
| src/infrastructure/db/repositories/DbUserMappingRepository.repository.ts | Removes legacy DB repository wrapper. |
| src/infrastructure/db/repositories/DbGuildRepository.repository.ts | Removes legacy DB repository wrapper. |
| src/infrastructure/db/repositories.ts | Removes legacy DB helper functions. |
| src/infrastructure/db/index.ts | Removes legacy DB exports. |
| src/infrastructure/db/client.ts | Removes legacy DB client/init function. |
| src/domain/entities/Issue.ts | Removes legacy domain Issue type. |
| src/domain/entities/index.ts | Removes legacy domain entities export. |
| src/core/orchestrations/user.orchestration.ts | Moves user mapping logic to DB integration-based orchestration. |
| src/core/orchestrations/repository.orchestration.ts | Moves guild repo config logic to DB integration-based orchestration. |
| src/core/orchestrations/llm.orchestration.ts | Routes LLM calls through LLM integration and DB integration. |
| src/core/orchestrations/issue.orchestration.ts | New issue orchestration using GitHub + DB integrations and event bus. |
| src/core/orchestrations/index.ts | Exports orchestrations as a single import surface. |
| src/core/events/index.ts | Exports event bus + event typing and provides singleton bus. |
| src/core/events/events.type.ts | Adds event payload typing map (analytics-focused). |
| src/core/events/event-bus.ts | Adds in-process fire-and-forget event bus implementation. |
| src/config/index.ts | Adds config barrel export. |
| src/config/env.ts | Adds standup channel env + generalizes LLM provider config. |
| src/application/usecases/issue.usecase.ts | Removes legacy issue use case implementation. |
| package.json | Adds OpenAI SDK dependency. |
| package-lock.json | Locks OpenAI + dependency updates. |
Comments suppressed due to low confidence (3)
src/config/env.ts:26
config.LLM.API_KEYis always sourced fromGEMINI_API_KEY, even whenLLM_PROVIDER_NAMEis set toopenai. This makes the “multiple providers” config misleading and likely breaks OpenAI usage. Consider using a provider-agnostic env var (e.g.LLM_API_KEY) or separate keys per provider (e.g.OPENAI_API_KEY/GEMINI_API_KEY) selected based onPROVIDER_NAME.
src/core/orchestrations/llm.orchestration.ts:5configis imported but never used in this module. Removing unused imports avoids confusion and keeps the orchestration focused on its actual dependencies.
src/core/orchestrations/llm.orchestration.ts:43- Log/error messages still refer to “Gemini” (
'Gemini raw response','Gemini API error') even though the integration can be backed by OpenAI as well. Make these messages provider-agnostic (or include the provider name) to avoid confusing operational logs.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import { handleMessageCreate } from './message-create.handler'; | ||
|
|
||
| export function registerHandlers(client: Client): void { | ||
| client.on('clientReady', handleClientReady); |
There was a problem hiding this comment.
client.on('clientReady', ...) is not a Discord.js client event, so handleClientReady will never fire. Use the standard 'ready' event (and keep naming consistent with Discord.js event names).
| }); | ||
|
|
||
| await llmIntegration.connect({ | ||
| apiKey: config.LLM.API_KEY, | ||
| providerName: config.LLM.PROVIDER_NAME, | ||
| }); | ||
|
|
||
| await dbIntegration.connect({ dbPath: './data/gitbot.db' }); | ||
|
|
||
| await startBot( | ||
| config.DISCORD.BOT_TOKEN, | ||
| config.DISCORD.CLIENT_ID, | ||
| config.DISCORD.GUILD_ID, |
There was a problem hiding this comment.
dbIntegration.connect() is called here and also inside startBot(), which will re-initialize/replace the singleton DB client and can lead to redundant initialization or SQLite locking issues. Connect the DB integration in one place (typically the entrypoint) and have downstream code assume it’s already connected.
|
|
||
| await deployBot(rest, CLIENT_ID, GUILD_ID); | ||
|
|
||
| registerHandlers(client); | ||
|
|
There was a problem hiding this comment.
startBot() currently calls dbIntegration.connect() with a hardcoded path, but the DB is already connected in main.bot.ts. This double-connect can overwrite the existing DbClient and cause operational issues. Prefer passing a connected client (or only connecting once) and avoid hardcoding ./data/gitbot.db in this layer.
| function handleGithubWebhook(req: Request, res: Response): void { | ||
| const event = req.header('x-github-event'); | ||
| const deliveryId = req.header('x-github-delivery'); | ||
|
|
||
| if (!event) { | ||
| res.status(400).json({ | ||
| ok: false, | ||
| error: 'Missing x-github-event header', | ||
| }); | ||
| return; | ||
| } | ||
|
|
||
| const payload = (req.body ?? {}) as GithubWebhookPayload; | ||
|
|
||
| if (event === 'ping') { | ||
| logger.info({ deliveryId }, 'Received GitHub webhook ping'); | ||
| res.status(200).json({ ok: true, message: 'pong' }); | ||
| return; | ||
| } | ||
|
|
||
| logger.info( | ||
| { | ||
| event, | ||
| deliveryId, | ||
| action: payload.action, | ||
| repository: payload.repository?.full_name ?? payload.repository?.name, | ||
| sender: payload.sender?.login, | ||
| }, | ||
| 'Received GitHub webhook event', | ||
| ); | ||
|
|
||
| // For now we acknowledge webhook delivery and log payload metadata. | ||
| // Domain handling can be plugged in here as use cases/events grow. | ||
| res.status(202).json({ ok: true, event }); | ||
| } |
There was a problem hiding this comment.
The GitHub webhook handler accepts POSTs without verifying the webhook signature (e.g. x-hub-signature-256) or otherwise authenticating the sender. This allows spoofed events and log spam. Add signature verification using a shared secret (and keep the raw body for HMAC verification via express.json({ verify }) or a raw-body middleware) before processing/acknowledging the event.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This pull request introduces a significant refactor of the application's core orchestration and data access layers, focusing on modularizing integrations, improving maintainability, and enhancing event handling. The changes involve moving business logic from use case files to orchestration modules, replacing direct database access with integration layers, removing legacy code, and introducing a new event bus system. Additionally, configuration and LLM (Large Language Model) handling are generalized to support multiple providers.