Skip to content

feat: add dynamic Slack App management#1710

Merged
qstearns merged 7 commits intomainfrom
slack-apps-auth/1-add-dynamic-slack-app-creation-in-gram
Feb 27, 2026
Merged

feat: add dynamic Slack App management#1710
qstearns merged 7 commits intomainfrom
slack-apps-auth/1-add-dynamic-slack-app-creation-in-gram

Conversation

@qstearns
Copy link
Contributor

@qstearns qstearns commented Feb 27, 2026

Summary

  • Adds server-side CRUD API for Slack apps with two-state lifecycle (unconfiguredactive), per-app credentials, system prompt, icon, and toolset associations
  • Adds dashboard UI: card grid list page, create dialog (name + icon + toolset picker), and detail page with status-dependent views (deep link + credentials form for unconfigured, MCPs/installations/system prompt for active)
  • Includes database migration, Goa design, SQLc queries, generated SDK + React Query hooks

Test plan

  • mise run db:reset && mise run db:migrate to apply migration
  • Navigate to Slack tab → card grid (or empty state if no apps)
  • Create a new Slack App with name, icon, and toolsets
  • Verify detail page shows unconfigured state with Slack deep link + credentials form
  • Paste credentials and configure → page refreshes to active state
  • Verify MCPs section links out to MCP detail pages
  • Verify system prompt auto-saves with debounce
  • Verify delete flow with confirmation dialog
  • tsc --noEmit passes

🤖 Generated with Claude Code


Open with Devin

@qstearns qstearns requested a review from a team as a code owner February 27, 2026 05:52
@vercel
Copy link

vercel bot commented Feb 27, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
gram-docs-redirect Ready Ready Preview, Comment Feb 27, 2026 11:28pm

Request Review

@changeset-bot
Copy link

changeset-bot bot commented Feb 27, 2026

⚠️ No Changeset found

Latest commit: c6255e2

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions
Copy link
Contributor

github-actions bot commented Feb 27, 2026

atlas migrate lint on server/migrations

Status Step Result
1 new migration file detected 20260227224912_add-slack-apps-tables.sql
ERD and visual diff generated View Visualization
No issues found View Report
Read the full linting report on Atlas Cloud

@blacksmith-sh

This comment has been minimized.

devin-ai-integration[bot]

This comment was marked as resolved.

@github-actions
Copy link
Contributor

atlas migrate lint on server/clickhouse/migrations

Status Step Result
No migration files detected  
ERD and visual diff generated View Visualization
No issues found View Report
Read the full linting report on Atlas Cloud

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View 9 additional findings in Devin Review.

Open in Devin Review

Comment on lines +290 to +294
useEffect(() => {
return () => {
if (debounceRef.current) clearTimeout(debounceRef.current);
};
}, []);
Copy link
Contributor

Choose a reason for hiding this comment

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

🟡 Debounced system prompt save is silently discarded on component unmount

In LeftPanel, when the user edits the system prompt, changes are debounced with an 800ms delay before saving. The useEffect cleanup at line 290-294 clears the pending timeout on unmount, which means the last edit is silently lost if the user navigates away within 800ms.

Root Cause & Impact

At client/dashboard/src/pages/slackapp/SlackAppDetail.tsx:282-288, handlePromptChange sets a debounced timer. At lines 290-294, the cleanup effect cancels any pending timer:

useEffect(() => {
    return () => {
      if (debounceRef.current) clearTimeout(debounceRef.current);
    };
  }, []);

If the user types in the system prompt and then immediately clicks "Delete App" or navigates away (e.g., via browser back button or clicking another sidebar item), the pending save is cancelled and the change is lost without any warning.

Impact: Users may lose system prompt edits without realizing it. A flush-on-unmount pattern (calling saveSystemPrompt with the current value in the cleanup) would prevent data loss.

Prompt for agents
In client/dashboard/src/pages/slackapp/SlackAppDetail.tsx, the useEffect cleanup at lines 290-294 clears the debounce timer on unmount but does not flush the pending save. To prevent data loss, the cleanup should check if there is a pending timeout and, if so, immediately call saveSystemPrompt with the current systemPrompt value before clearing the timer. You will need to use a ref to track the latest systemPrompt value so the cleanup closure has access to it. For example, add a latestPromptRef that is updated in handlePromptChange, then in the cleanup: if debounceRef.current is set, clear the timeout and call saveSystemPrompt(latestPromptRef.current).
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@qstearns qstearns force-pushed the slack-apps-auth/1-add-dynamic-slack-app-creation-in-gram branch from 6fafbd3 to b1778cf Compare February 27, 2026 22:37
devin-ai-integration[bot]

This comment was marked as resolved.

@qstearns qstearns force-pushed the slack-apps-auth/1-add-dynamic-slack-app-creation-in-gram branch from b1778cf to 7c1a08c Compare February 27, 2026 22:52
qstearns and others added 6 commits February 27, 2026 15:13
Adds server-side support for creating, configuring, updating, and
deleting Slack apps. Apps use a two-state lifecycle (unconfigured/active)
with per-app credentials, system prompt, icon, and toolset associations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds card grid list view, create dialog, and detail page with
status-dependent UI (unconfigured: Slack deep link + credentials form,
active: MCPs, installations, system prompt, chat logs placeholder).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds server-side support for creating, configuring, updating, and
deleting Slack apps. Apps use a two-state lifecycle (unconfigured/active)
with per-app credentials, system prompt, icon, and toolset associations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@qstearns qstearns force-pushed the slack-apps-auth/1-add-dynamic-slack-app-creation-in-gram branch from 7c1a08c to 739f56e Compare February 27, 2026 23:16
- Verify each toolset belongs to the same project before attaching
- Wrap app creation + toolset attachment in a single DB transaction

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 new potential issue.

View 18 additional findings in Devin Review.

Open in Devin Review

},
);
},
[app.id, queryClient, updateMutation],
Copy link
Contributor

Choose a reason for hiding this comment

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

🟡 updateMutation in useCallback deps causes saveSystemPrompt to be recreated on every mutation state change

Including updateMutation (the entire UseMutationResult object) in the useCallback dependency array for saveSystemPrompt is incorrect — the mutation result object changes identity on every mutation state transition (idle→pending→success/error→idle), causing saveSystemPrompt to be recreated unnecessarily on each state change.

Detailed Explanation

updateMutation at client/dashboard/src/pages/slackapp/SlackAppDetail.tsx:242 is the return value of useUpdateSlackAppMutation(), which wraps React Query's useMutation. The returned object changes reference whenever the mutation state changes.

At line 279, updateMutation is listed as a dependency:

[app.id, queryClient, updateMutation]

This means every time a debounced save fires (calling mutate), the mutation's isPending state change forces saveSystemPrompt to be recreated. While mutate itself is stable per React Query, including the whole result object defeats the purpose of useCallback and could cause subtle issues if the debounce timer fires between re-renders.

The fix is to either remove updateMutation from the dependency array (since mutate is stable), or extract just updateMutation.mutate into a ref.

Suggested change
[app.id, queryClient, updateMutation],
[app.id, queryClient],
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@qstearns qstearns merged commit 87feb39 into main Feb 27, 2026
36 checks passed
@qstearns qstearns deleted the slack-apps-auth/1-add-dynamic-slack-app-creation-in-gram branch February 27, 2026 23:43
@github-actions github-actions bot locked and limited conversation to collaborators Feb 27, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants