Skip to content

Conversation

@shawntz
Copy link

@shawntz shawntz commented Jan 3, 2026

Description

Allows boards to sync GitHub pull requests and issues to Fizzy cards via webhooks. Board admins configure webhooks directly in their GitHub repository settings—no OAuth or server-side GitHub App required. Moreover, allows boards to sync Slack messages to Fizzy cards via webhooks and control card state through emoji reactions. Board admins configure webhooks using their Slack app settings; again, no OAuth or server-side Slack App required beyond basic bot setup.

Motivation

Development teams often track work across multiple tools. This integration brings GitHub activity into Fizzy automatically, reducing manual card creation and keeping work visible in one place.

The webhook-only approach keeps setup simple: no API tokens to manage, no rate limits to worry about, and users control the integration entirely from GitHub's UI.

Furthermore, teams already discuss work in Slack. This integration captures those conversations as cards in Fizzy automatically and enables lightweight workflow control through emoji reactions, reducing context switching and keeping work discussions linked to trackable cards.

The webhook-only approach keeps setup straightforward: configure once in Slack, automatic bot user detection, and reaction-based actions provide intuitive card management without leaving Slack.

GitHub Integration

How It Works

Setup

  1. Board admin adds a repository in board settings
  2. Fizzy generates a unique webhook URL and secret
  3. Admin configures the webhook in GitHub repository settings
  4. GitHub events automatically create and update cards

Event Support

  • Pull requests (opened, edited, closed, merged, reopened)
  • Issues (opened, edited, closed, reopened)
  • Comments on PRs and issues
  • PR reviews

Card Creation

  • Creates one card per issue/PR
  • Updates existing cards when events arrive
  • System user attribution (no GitHub→Fizzy user mapping needed)
  • Automatically creates cards for pre-existing issues/PRs when comments arrive

Implementation

Database

  • github_integrations - board-scoped repository configurations with webhook secrets
  • github_items - links cards to GitHub issues/PRs (prevents duplicates)
  • github_integration_deliveries - webhook delivery logs for debugging
  • account_github_settings - account-level event filtering

Controllers

  • Standard CRUD for integration management (board-scoped)
  • Unauthenticated webhook receiver with HMAC-SHA256 signature verification
  • Account settings for global preferences

Models

  • GithubIntegration - sync logic and event filtering
  • GithubIntegration::Colored - color picker support (reuses existing Color pattern)
  • GithubItem - join model
  • Card#add_github_comment and Card#add_github_review - extends existing card model

Jobs

  • Github::WebhookProcessorJob - async processing via Solid Queue
  • Idempotent handling (duplicate webhooks don't duplicate cards)
  • Sets Current.user for event callbacks

Security

  • HMAC-SHA256 webhook signature verification
  • Constant-time comparison
  • Per-integration secrets
  • Multi-tenant scoping throughout

UI

Board Settings

  • Shows repository count
  • Links to integration management page

Integration Management

  • List view with colored indicators
  • Modal color picker (reuses existing popup pattern)
  • Delete with confirmation

Integration Detail

  • Displays webhook URL and secret
  • Event type toggles
  • Setup instructions

Tested

  • Webhook signature verification
  • Card creation and updates
  • Event filtering (board and account level)
  • Multi-tenant isolation
  • Idempotent processing
  • Pre-existing issue/PR handling

Limitations

  • One-way sync (GitHub → Fizzy only)
  • No historical backfill (webhook-based, new events only)
  • Pre-existing items created when first comment arrives
  • Repository field immutable after creation

Migration

bin/rails db:migrate

Creates four tables: github_integrations, github_items, github_integration_deliveries, account_github_settings.

Slack Integration

How It Works

Setup

  1. Board admin creates Slack integration in board settings
  2. Fizzy generates unique webhook URL
  3. Admin configures Slack app with webhook URL and scopes
  4. Admin configures emoji-to-action mappings in Fizzy
  5. Bot user ID auto-detected from first webhook (no manual configuration)
  6. Invite bot to Slack channel

Message Syncing

  • @mention bot in Slack → Creates card in Fizzy
  • Bot replies in thread with card link and available emoji actions
  • Bot mention automatically stripped from card title/description
  • Cards attributed to account owner (not system user)
  • Thread replies sync as card comments (optional)

Emoji Reaction Actions

  • React with configured emoji → Triggers action on card
  • Supported actions:
    • Move to specific column
    • Close card
    • Postpone (Not Now)
    • Reopen card
  • State transitions handled automatically (e.g., postpone → move resumes first)
  • Bot confirms action in thread with card link
Screenshot 2026-01-02 at 4 44 07 PM

@mentioning the bot in Slack creates a card. Bot replies with card link and emoji action instructions.

Screenshot 2026-01-02 at 4 44 29 PM

Reacting with mapped emoji triggers action. Bot confirms with "✅ Card moved to Done" message.

Screenshot 2026-01-02 at 3 37 23 PM

Configure emoji reactions to map to column moves, close, postpone, or reopen actions.

Implementation

Database

  • slack_integrations - board-scoped channel configurations with webhook secrets
  • slack_items - links cards to Slack messages (prevents duplicates, enables reactions)
  • slack_integration_deliveries - webhook delivery logs for debugging
  • account_slack_settings - account-level event filtering
  • bot_user_id and bot_oauth_token - auto-detected from webhooks and user input
  • emoji_action_mappings - JSON column storing emoji→action configuration

Controllers

  • Standard CRUD for integration management (board-scoped)
  • Unauthenticated webhook receiver with HMAC-SHA256 signature verification
  • Account settings for global preferences
  • Activation/deactivation toggle controller

Models

  • SlackIntegration - sync logic, bot mention detection, emoji action execution
  • SlackIntegration#message_mentions_bot? - checks for bot user ID in message
  • SlackIntegration#send_thread_reply - posts confirmation to thread
  • SlackIntegration#send_emoji_action_feedback - posts action result to thread
  • SlackIntegration#execute_emoji_action - handles all emoji actions with state transitions
  • SlackIntegration#strip_bot_mention - cleans message text for card content
  • SlackIntegration::Colored - color picker support
  • SlackItem - join model tracking message timestamp
  • Card#add_slack_comment and Card#add_slack_reaction - extends existing card model

Jobs

  • Slack::WebhookProcessorJob - async processing via Solid Queue
  • Idempotent handling (duplicate webhooks don't duplicate cards)
  • Sets Current.user to account owner for proper attribution

Security

  • HMAC-SHA256 webhook signature verification (Slack signing secret)
  • Constant-time comparison
  • Per-integration secrets
  • Multi-tenant scoping throughout
  • Bot token stored securely for outbound messages

Auto-Detection

  • Bot user ID automatically extracted from webhook authorizations array
  • Eliminates error-prone manual configuration
  • Updates on every webhook if changed
Screenshot 2026-01-02 at 4 45 43 PM

Customizable Slack channel integrations in Fizzy UI.

Screenshot 2026-01-02 at 4 45 52 PM Screenshot 2026-01-02 at 4 46 00 PM

Bot User ID is auto-detected. Setup instructions guide through Slack app configuration with specific scopes and events.

UI

Board Settings

  • Shows Slack integration count
  • Links to integration management page
  • Inline toggle for activation/deactivation

Integration Management

  • List view with colored indicators and active/inactive badges
  • Delete with confirmation
  • Quick activation toggles

Integration Detail

  • Displays webhook URL and signing secret (masked)
  • Auto-detected bot user ID (read-only)
  • Bot OAuth token input
  • Event type toggles (messages, thread replies, reactions)
  • Emoji action mapping configuration with dropdowns
  • Recent webhook delivery log with status
  • Comprehensive troubleshooting section with Docker log examples

Integration Edit

  • Channel name and workspace domain
  • Signing secret input
  • Bot OAuth token input (for thread replies)
  • Bot User ID (auto-detected, read-only)
  • Event sync toggles
  • Emoji action mappings with visual emoji picker

Account Settings

  • Global toggle for allowing Slack integrations
  • Event type filtering (can disable specific events account-wide)

Features

Smart State Transitions

  • Postpone → Move to Column: Automatically resumes card before moving
  • Closed → Postpone: Reopens card before postponing
  • Postpone → Close: Resumes before closing
  • Move to Column on closed/postponed card: Handles state properly
  • Reopen action: Works for both closed and postponed cards

Proper Attribution

  • Cards created by account owner, not system user
  • Shows "Added by [Your Name]" instead of "Added by System"
  • Event tracking attributes actions to owner

Thread Feedback

  • Card creation confirmation with link
  • Emoji action confirmation ("✅ Card moved to Done")
  • All messages include direct card link
  • Feedback only for successful actions (skipped actions silent)
Screenshot 2026-01-02 at 4 48 28 PM

Caption: Cards created from Slack show account owner as creator, not "System".

Tested

  • Webhook signature verification
  • Card creation from @mentions
  • Bot mention stripping from title/description
  • Bot user ID auto-detection from webhooks
  • Emoji action mappings (all action types)
  • State transitions between all states
  • Thread reply confirmations
  • Event filtering (board and account level)
  • Multi-tenant isolation
  • Idempotent processing
  • Account owner attribution
  • Activation/deactivation

Configuration

Required Slack App Scopes

  • channels:history - Receive channel messages
  • reactions:read - Receive emoji reactions
  • chat:write - Send thread reply confirmations

Required Slack App Events

  • message.channels - Channel messages
  • reaction_added - Emoji reactions

Setup Flow

  1. Create Slack integration in Fizzy (generates webhook URL)
  2. Create Slack app at api.slack.com/apps
  3. Add Bot Token Scopes in OAuth & Permissions
  4. Enable Event Subscriptions with Fizzy webhook URL
  5. Subscribe to bot events
  6. Copy signing secret to Fizzy
  7. Copy Bot User OAuth Token to Fizzy
  8. Reinstall Slack app to workspace
  9. Invite bot to channel (/invite @BotName)
  10. Configure emoji mappings in Fizzy
  11. Test with @mention
Screenshot 2026-01-02 at 4 45 35 PM

Upgraded webhooks UI to separate out incoming/outgoing webhooks.

Limitations

  • One-way sync (Slack → Fizzy only)
  • No historical backfill (webhook-based, new events only)
  • Requires @mention for card creation (prevents channel spam)
  • Emoji reactions only work on messages that created cards
  • Thread replies sync but don't create new cards
  • One integration per channel (unique constraint on channel_id per board)

Migration

bin/rails db:migrate

Creates four tables: slack_integrations, slack_items, slack_integration_deliveries, account_slack_settings.

Adds bot_user_id and bot_oauth_token columns to slack_integrations.

Cheers,
Shawn Schwartz (@shawntz) (ex-Slack Data)

Introduces models, controllers, jobs, and views for integrating GitHub repositories with boards. Supports syncing pull requests, issues, comments, and reviews as cards and comments, with per-account and per-integration event toggles. Adds webhook endpoint, delivery tracking, admin UI for managing integrations, and migrations for new tables. Updates routes and recurring tasks for delivery cleanup.
Introduces a new string column 'color' with a default value to the github_integrations table to support color customization.
Introduces Slack integration models, controllers, jobs, and views to support syncing messages, thread replies, and reactions from Slack channels to cards. Adds emoji-to-action mapping for Slack reactions, global and per-integration event controls, delivery tracking, and feedback to Slack. Includes migrations, tests, and documentation for the new Slack integration features.
Refactors the webhooks index page to separate incoming and outgoing webhooks into distinct panels. Adds descriptions for each section, renders partials for incoming integrations (GitHub, Slack), and updates the outgoing webhooks list and creation button with improved layout and permissions.
@shawntz shawntz marked this pull request as ready for review January 3, 2026 01:09
Copilot AI review requested due to automatic review settings January 3, 2026 01:09
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds comprehensive GitHub and Slack webhook integrations to Fizzy, enabling automatic card creation from GitHub pull requests/issues and Slack messages, plus emoji reaction-based workflow actions. The implementation includes webhook signature verification, async job processing, account-level settings, and extensive UI for configuration.

Key Changes:

  • Webhook-based integrations for GitHub (PRs, issues, comments, reviews) and Slack (messages, threads, emoji reactions)
  • Emoji reaction actions for Slack that can move cards, close, postpone, or reopen them
  • Account-level and board-level event filtering
  • Auto-detection of Slack bot user ID from webhook payloads

Reviewed changes

Copilot reviewed 74 out of 74 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
app/models/slack_integration.rb Core Slack integration logic with bot mentions, emoji actions, and thread replies
app/models/github_integration.rb GitHub webhook processing for PRs and issues with HMAC verification
app/controllers/slack/webhooks_controller.rb Unauthenticated Slack webhook endpoint with signature verification
app/controllers/github/webhooks_controller.rb Unauthenticated GitHub webhook endpoint with HMAC-SHA256 verification
app/jobs/slack/webhook_processor_job.rb Async Slack webhook processing with account owner attribution
app/jobs/github/webhook_processor_job.rb Async GitHub webhook processing with system user attribution
db/migrate/* Eight migrations creating integration tables and settings
test/models/* Comprehensive test coverage for models and integrations
app/views/slack_integrations/* UI for managing Slack integrations with emoji mapping configuration
app/views/github_integrations/* UI for managing GitHub integrations with color-coded repositories
config/recurring.yml Cleanup job for stale GitHub delivery records
docs/*.md Detailed documentation for both integrations

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

card,
script_name: account.slug,
host: Rails.application.config.action_mailer.default_url_options[:host],
protocol: 'http'
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

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

The card_url method uses hardcoded protocol: 'http' which should typically use https in production environments. This could cause security warnings or issues when accessing the URLs from Slack.

Suggested change
protocol: 'http'
protocol: 'https'

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +36
def emoji_action_mappings
value = read_attribute(:emoji_action_mappings)
return {} if value.nil?
return value if value.is_a?(Hash)

# If it's a string, try to parse it (shouldn't happen with :json attribute, but defensive)
if value.is_a?(String)
begin
parsed = JSON.parse(value)
return parsed.is_a?(Hash) ? parsed : {}
rescue JSON::ParserError
Rails.logger.error "Failed to parse emoji_action_mappings: #{value}"
return {}
end
end

{}
end
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

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

The emoji_action_mappings getter method has defensive error handling and logging, but returns an empty hash on JSON parse errors. Consider whether this silent failure is appropriate, or if validation should prevent invalid JSON from being stored in the first place.

Copilot uses AI. Check for mistakes.
Comment on lines +27 to +29
cleanup_github_integration_deliveries:
command: "GithubIntegration::Delivery.cleanup"
schedule: every 4 hours at minute 55
Copy link

Copilot AI Jan 3, 2026

Choose a reason for hiding this comment

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

The cleanup_github_integration_deliveries recurring job references GithubIntegration::Delivery.cleanup, but there's no corresponding cleanup_slack_integration_deliveries job for SlackIntegration::Delivery.cleanup, even though both delivery models implement the same cleanup method. This inconsistency could lead to unbounded growth of Slack delivery records.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@northeastprince northeastprince left a comment

Choose a reason for hiding this comment

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

I would create a Github and Slack namespace as opposed to starting multiple classes with the same prefix.

@shawntz
Copy link
Author

shawntz commented Jan 4, 2026

I would create a Github and Slack namespace as opposed to starting multiple classes with the same prefix.

thanks @northeastprince -- appreciate the feedback; that's a good point. i'll refactor this PR accordingly ✌️

@jorgemanrubia
Copy link
Member

Thanks @shawntz, we really appreciate your work here. Integrating with third-party systems is a very interesting area of functionality for us, too. The problem here is that this is a very large change, and we have some ideas about how to implement it that would differ quite a bit regarding this proposal. The differences are too big to correct via PR reviewing so I need to close this one without merging. Sorry about that, and thanks again for your effort.

@shawntz
Copy link
Author

shawntz commented Jan 7, 2026

Thanks @jorgemanrubia – appreciate the update and totally understand. Not sure what your current plans for implementation are, but I could envision a similar type of "open a door to" workflow like those in Basecamp. Curious to see where things go with this!

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.

3 participants