Skip to content

feat: flow item on telegram#231

Merged
hmbanan666 merged 1 commit intomainfrom
flow-item
Oct 17, 2025
Merged

feat: flow item on telegram#231
hmbanan666 merged 1 commit intomainfrom
flow-item

Conversation

@hmbanan666
Copy link
Copy Markdown
Collaborator

@hmbanan666 hmbanan666 commented Oct 17, 2025

Summary by CodeRabbit

  • New Features

    • Added notifications for flow item creation events, sending summarized messages with clickable links to Atrium team channels.
  • Chores

    • Removed unused code blocks related to message delivery systems.

@hmbanan666 hmbanan666 self-assigned this Oct 17, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Oct 17, 2025

Walkthrough

This PR introduces a new FlowItemCreated event to the queue system, enabling flow item creation events to be published and consumed across the application. It includes event type definitions, a Flow entity for consuming events, Telegram message handlers to notify about created items, and event publishing when flow items are created. Commented-out code in daily-report.ts is removed.

Changes

Cohort / File(s) Summary
Event Type Definition
packages/queue/src/repository/types.ts
Adds flowItemCreated enum member to Events, introduces FlowItemCreatedData type with itemId, type, title, and description fields, and exports FlowItemCreated interface extending BaseEventMessage
Flow Entity
packages/queue/src/repository/entities/flow.ts
New Flow entity class extending Entity, registered with name "flow" and empty eventsToConsume array
Entity Exports
packages/queue/src/repository/entities/index.ts
Exports Flow entity from ./flow
Queue Integration
packages/queue/src/repository/index.ts
Adds flow: Flow property to QueueRepository, initialized as new Flow(this)
Telegram Consumer
packages/queue/src/repository/entities/telegram.ts
Adds Events.flowItemCreated to Telegram entity's eventsToConsume list
Event Publishing
apps/web-app/server/tasks/ai/weekly-report.ts
Imports FlowItemCreated and queue utilities; publishes FlowItemCreated event after creating a flow item with itemId, type, title, and description
Event Handler
apps/core-telegram/server/services/queue/index.ts
Imports FlowItemCreated; registers and implements handleFlowItemCreated to send Telegram messages with flow item details and Atrium deep link
Dead Code Removal
apps/web-app/server/tasks/ai/daily-report.ts
Removes commented-out block containing Atrium bot messaging code

Sequence Diagram

sequenceDiagram
    participant WA as web-app<br/>weekly-report
    participant Queue as Queue System
    participant CT as core-telegram<br/>handler
    participant TG as Telegram

    WA->>WA: Create flow item
    WA->>Queue: Publish FlowItemCreated event
    Queue->>Queue: Event enqueued
    Queue->>CT: Dispatch to handler
    CT->>CT: Format item summary<br/>& description
    CT->>TG: Send message with<br/>Atrium deep link
    TG-->>CT: Message sent
    CT-->>Queue: Handler returns true
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

The changes span multiple interconnected files across the queue package and consuming applications, introducing a new event type with corresponding entity, publisher, and handler. While individual changes follow consistent patterns, the distributed nature and mix of type definitions, entity structure, event publishing logic, and Telegram integration require attention across several domains.

Possibly related PRs

  • feat: atrium telegram bot #77: Adds Atrium bot integration (useAtriumBot) that the FlowItemCreated handler directly depends on for sending deep-link messages to Telegram.
  • feat: package queue renamed and updated #213: Extends the queue package's event types and consumer system; this PR builds on that foundation by adding Flow entity and flowItemCreated event.
  • chore: some updates #165: Modifies the same daily-report.ts task to remove or refactor Atrium/Telegram integration, creating overlapping changes to the same file.

Poem

🐰 A new event hops into the queue,
Flow items created, all shiny and new!
From weekly reports to Telegram's call,
The rabbit orchestrates messages for all. 🎯📨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "feat: flow item on telegram" clearly summarizes the primary capability being added in this PR. The changeset establishes a complete FlowItemCreated event-driven system with infrastructure components (new Flow entity, event type definitions, queue repository integration), and the main user-facing feature is that the Telegram service now handles and responds to flow item events by sending Atrium messages. The title accurately captures this from a feature perspective, and while it doesn't detail every infrastructure component, the requirement acknowledges that covering every detail is not necessary. The title is specific, concise, and unambiguously communicates what has been implemented.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch flow-item

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 and usage tips.

@sonarqubecloud
Copy link
Copy Markdown

@hmbanan666 hmbanan666 merged commit 4ba71c3 into main Oct 17, 2025
7 of 8 checks passed
@hmbanan666 hmbanan666 deleted the flow-item branch October 17, 2025 15:04
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (4)
packages/queue/src/repository/index.ts (1)

5-8: Make repository members readonly.

Prevents accidental reassignment and clarifies intent.

Apply:

-class QueueRepository extends Repository {
-  flow: Flow = new Flow(this)
-  notification: Notification = new Notification(this)
-  telegram: Telegram = new Telegram(this)
-  ticket: Ticket = new Ticket(this)
+class QueueRepository extends Repository {
+  readonly flow: Flow = new Flow(this)
+  readonly notification: Notification = new Notification(this)
+  readonly telegram: Telegram = new Telegram(this)
+  readonly ticket: Ticket = new Ticket(this)
apps/web-app/server/tasks/ai/weekly-report.ts (1)

80-86: Add idempotency to prevent duplicate weekly items/events.

Retries or overlapping schedules can create multiple “weekly_task_report” items for the same week. Use a deterministic key (e.g., year-week) and upsert/guard before create.

Example approach:

  • Compute key = ${format(new Date(), 'yyyy')}-${format(new Date(), 'II')} (ISO week).
  • Add a unique DB constraint on (type, key) or use create/update with where unique.
apps/core-telegram/server/services/queue/index.ts (1)

64-90: Consider extracting a helper for Telegram startapp links.

Both handleFlowItemCreated and handleUserBeaconOnEpicCommentCreated follow a similar pattern:

  • Create a separator constant with value 'zzzzz'
  • Build startAppData using the same separator pattern
  • Send messages with inline keyboards containing startapp URLs

Consider extracting a helper function to reduce duplication:

function buildStartAppLink(entityType: string, entityId: string): string {
  const separator = 'zzzzz'
  const startAppData = `${entityType}${separator}${entityId}`
  return `https://t.me/sushi_atrium_bot/app?startapp=${startAppData}`
}

Then use it in both handlers:

const url = buildStartAppLink('flow', data.itemId)
// ...
reply_markup: {
  inline_keyboard: [[{
    text: '👉 Открыть Атриум',
    url,
  }]]
}
packages/queue/src/repository/types.ts (1)

40-48: Consider refining the type field for better type safety.

The type field in FlowItemCreatedData is currently typed as string, which allows any string value. If the type field has a known set of possible values (e.g., "task", "milestone", "note"), consider using a string literal union or enum for better type safety and IDE autocomplete.

Example:

type FlowItemType = 'task' | 'milestone' | 'note' | 'other'

type FlowItemCreatedData = {
  itemId: string
  type: FlowItemType
  title: string
  description: string
}

This would prevent typos and make the API more discoverable.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dff39c1 and cc98011.

📒 Files selected for processing (8)
  • apps/core-telegram/server/services/queue/index.ts (3 hunks)
  • apps/web-app/server/tasks/ai/daily-report.ts (0 hunks)
  • apps/web-app/server/tasks/ai/weekly-report.ts (2 hunks)
  • packages/queue/src/repository/entities/flow.ts (1 hunks)
  • packages/queue/src/repository/entities/index.ts (1 hunks)
  • packages/queue/src/repository/entities/telegram.ts (1 hunks)
  • packages/queue/src/repository/index.ts (1 hunks)
  • packages/queue/src/repository/types.ts (2 hunks)
💤 Files with no reviewable changes (1)
  • apps/web-app/server/tasks/ai/daily-report.ts
🧰 Additional context used
🧬 Code graph analysis (4)
apps/core-telegram/server/services/queue/index.ts (2)
packages/queue/src/repository/types.ts (1)
  • FlowItemCreated (46-48)
apps/core-telegram/server/services/telegram/atrium-bot.ts (1)
  • useAtriumBot (184-190)
packages/queue/src/repository/entities/flow.ts (1)
packages/queue/src/repository/index.ts (1)
  • repository (11-11)
apps/web-app/server/tasks/ai/weekly-report.ts (1)
packages/queue/src/repository/types.ts (1)
  • FlowItemCreated (46-48)
packages/queue/src/repository/index.ts (1)
packages/queue/src/repository/entities/flow.ts (1)
  • Flow (4-12)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (7)
packages/queue/src/repository/entities/index.ts (1)

1-1: LGTM: barrel now exposes Flow.

Simplifies downstream imports.

packages/queue/src/repository/entities/flow.ts (1)

4-12: LGTM: Flow entity scaffolded correctly.

Matches repository wiring; safe to extend with producers/consumers later.

apps/web-app/server/tasks/ai/weekly-report.ts (1)

1-1: ****

The concern about an alias mismatch is incorrect. The codebase shows a normal layered dependency structure: @roll-stack/queue is the actual package name (defined in packages/queue/package.json), and internally it depends on @nextorders/queue (an external upstream package). All imports from consuming apps, including the reviewed file, correctly use @roll-stack/queue. No build or runtime issues from this structure.

Likely an incorrect or invalid review comment.

apps/core-telegram/server/services/queue/index.ts (2)

1-1: LGTM!

The import statement correctly includes the new FlowItemCreated type.


13-13: LGTM!

Handler registration follows the existing pattern and is correctly integrated.

packages/queue/src/repository/types.ts (2)

6-6: LGTM!

The new event type follows the existing naming convention and is properly integrated into the enum.


9-9: LGTM!

The union type is correctly updated to include the new FlowItemCreated event.

Comment on lines +64 to +90
async function handleFlowItemCreated(data: FlowItemCreated['data']): Promise<boolean> {
try {
const separator = 'zzzzz'
const startAppData = `flow${separator}${data.itemId}`

// Get first words
const messageIntro = data.description.split(' ').slice(0, 45).join(' ')
const preparedMessage = `${messageIntro}...\n\nОстальное в Атриуме 🙃`

await useAtriumBot().api.sendMessage(telegram.teamGroupId, preparedMessage, {
link_preview_options: {
is_disabled: true,
},
reply_markup: {
inline_keyboard: [[{
text: '👉 Открыть Атриум',
url: `https://t.me/sushi_atrium_bot/app?startapp=${startAppData}`,
}]],
},
})

return true
} catch (error) {
console.error(error)
return false
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add input validation and fix truncation logic.

The function has several issues:

  1. Missing input validation: No checks that data.description exists or is a string before calling .split(), which could cause runtime errors.
  2. Incorrect truncation logic: The ellipsis ... is always appended, even when the description is shorter than 45 words.
  3. Fragile text splitting: Using split(' ') doesn't handle multiple consecutive spaces, newlines, or other whitespace characters well.

Apply this diff to add validation and improve truncation:

 async function handleFlowItemCreated(data: FlowItemCreated['data']): Promise<boolean> {
   try {
+    if (!data.description || typeof data.description !== 'string') {
+      console.error('Invalid description in FlowItemCreated event')
+      return false
+    }
+
     const separator = 'zzzzz'
     const startAppData = `flow${separator}${data.itemId}`
 
-    // Get first words
-    const messageIntro = data.description.split(' ').slice(0, 45).join(' ')
-    const preparedMessage = `${messageIntro}...\n\nОстальное в Атриуме 🙃`
+    // Get first 45 words, handling whitespace properly
+    const words = data.description.trim().split(/\s+/)
+    const messageIntro = words.slice(0, 45).join(' ')
+    const preparedMessage = words.length > 45 
+      ? `${messageIntro}...\n\nОстальное в Атриуме 🙃`
+      : `${messageIntro}\n\nОстальное в Атриуме 🙃`
 
     await useAtriumBot().api.sendMessage(telegram.teamGroupId, preparedMessage, {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async function handleFlowItemCreated(data: FlowItemCreated['data']): Promise<boolean> {
try {
const separator = 'zzzzz'
const startAppData = `flow${separator}${data.itemId}`
// Get first words
const messageIntro = data.description.split(' ').slice(0, 45).join(' ')
const preparedMessage = `${messageIntro}...\n\nОстальное в Атриуме 🙃`
await useAtriumBot().api.sendMessage(telegram.teamGroupId, preparedMessage, {
link_preview_options: {
is_disabled: true,
},
reply_markup: {
inline_keyboard: [[{
text: '👉 Открыть Атриум',
url: `https://t.me/sushi_atrium_bot/app?startapp=${startAppData}`,
}]],
},
})
return true
} catch (error) {
console.error(error)
return false
}
}
async function handleFlowItemCreated(data: FlowItemCreated['data']): Promise<boolean> {
try {
if (!data.description || typeof data.description !== 'string') {
console.error('Invalid description in FlowItemCreated event')
return false
}
const separator = 'zzzzz'
const startAppData = `flow${separator}${data.itemId}`
// Get first 45 words, handling whitespace properly
const words = data.description.trim().split(/\s+/)
const messageIntro = words.slice(0, 45).join(' ')
const preparedMessage = words.length > 45
? `${messageIntro}...\n\nОстальное в Атриуме 🙃`
: `${messageIntro}\n\nОстальное в Атриуме 🙃`
await useAtriumBot().api.sendMessage(telegram.teamGroupId, preparedMessage, {
link_preview_options: {
is_disabled: true,
},
reply_markup: {
inline_keyboard: [[{
text: '👉 Открыть Атриум',
url: `https://t.me/sushi_atrium_bot/app?startapp=${startAppData}`,
}]],
},
})
return true
} catch (error) {
console.error(error)
return false
}
}
🤖 Prompt for AI Agents
In apps/core-telegram/server/services/queue/index.ts around lines 64 to 90,
validate that data.description exists and is a string (fallback to empty string
or return false) before processing; split words using a robust whitespace
pattern (e.g. description.trim().split(/\s+/) or match word tokens) instead of
split(' ') to handle multiple spaces/newlines; only append the ellipsis when the
description was actually truncated (i.e., when word count > 45) and otherwise
use the full description without adding '...'; ensure preparedMessage is built
from the joined first 45 words (no extra spaces) and add the trailing hint text
unchanged.

Comment on lines +88 to +94
// Push Event
await queue.publish<FlowItemCreated>(Events.flowItemCreated, {
itemId: item.id,
type: item.type,
title: item.title,
description: item.description ?? '',
})
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Event payload may carry long PII-heavy content; clamp or slim it.

Weekly report text can be large and contain staff/task details. Sending full description over the bus risks privacy exposure and broker/message-size issues. Prefer publishing only identifiers, or at least truncate description.

Apply minimal change to clamp payload:

-      await queue.publish<FlowItemCreated>(Events.flowItemCreated, {
+      await queue.publish<FlowItemCreated>(Events.flowItemCreated, {
         itemId: item.id,
         type: item.type,
         title: item.title,
-        description: item.description ?? '',
+        description: (item.description ?? '').slice(0, 2000),
       })

Longer-term: publish only itemId and let consumers load details from DB.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Push Event
await queue.publish<FlowItemCreated>(Events.flowItemCreated, {
itemId: item.id,
type: item.type,
title: item.title,
description: item.description ?? '',
})
// Push Event
await queue.publish<FlowItemCreated>(Events.flowItemCreated, {
itemId: item.id,
type: item.type,
title: item.title,
description: (item.description ?? '').slice(0, 2000),
})
🤖 Prompt for AI Agents
In apps/web-app/server/tasks/ai/weekly-report.ts around lines 88 to 94, the
event payload includes the full item.description which may be large and contain
PII; replace that with a clamped/trimmed value (e.g., limit to a small fixed
length like 200 characters and optionally strip newlines) or omit it entirely so
the message only carries identifiers (itemId, type, title) and minimal text;
implement this minimal change now (truncate or set to empty string/null), and
note longer-term to publish only itemId and let consumers fetch full details
from the DB.

Comment on lines 10 to 13
Events.ticketMessageCreated,
Events.notificationUserBeaconOnEpicCommentCreated,
Events.flowItemCreated,
],
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Subscription looks good; verify consumer handler and idempotency.

Telegram is now subscribed to flowItemCreated. Ensure a concrete handler exists and deduplicates to avoid duplicate Telegram/Atrium sends on retries/at‑least‑once delivery.

Run:


🏁 Script executed:

#!/bin/bash
# 1) Confirm a handler exists
rg -nP -C2 '\bflowItemCreated\b' apps/core-telegram/server/services/queue -S

# 2) Check for dedup/idempotency in the handler
rg -nP -C2 'dedup|idempot|once|messageId|processed' apps/core-telegram/server/services/queue -S

Length of output: 455


🏁 Script executed:

#!/bin/bash
# Find and inspect handleFlowItemCreated implementation
rg -nA20 'handleFlowItemCreated\s*=' apps/core-telegram/server/services/queue -S

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check for any dedup/idempotency patterns in broader scope
rg -nP 'dedup|idempot|once|messageId|processed' apps/core-telegram/server/services -S

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for event processing patterns or message tracking in queue handlers
rg -nP 'cache|Map|Set|Store|tracking|duplicate' apps/core-telegram/server/services/queue -S

Length of output: 307


🏁 Script executed:

#!/bin/bash
# Find where handleFlowItemCreated is imported or defined
rg -nP 'handleFlowItemCreated' apps/core-telegram --type ts --type tsx

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Check the index.ts file to see the full imports and structure
cat apps/core-telegram/server/services/queue/index.ts

Length of output: 2915


🏁 Script executed:

#!/bin/bash
# Look for queue handlers directory or handlers file
fd -type f -name '*.ts' -path '*queue*' apps/core-telegram/server | head -20

Length of output: 170


Handler exists but lacks idempotency protection; duplicates will be sent on retries.

Verification confirms handleFlowItemCreated sends a message to telegram.teamGroupId without any dedup mechanism. Under at-least-once delivery, event reprocessing causes duplicate Telegram messages in the group. All three handlers (ticketMessageCreated, userBeaconOnEpicCommentCreated, flowItemCreated) share this vulnerability.

Add idempotency: track processed event IDs (e.g., in a cache or database) or make the handler idempotent before consuming this event.

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.

1 participant