feat(conversations): use canonical slack permalink for support ticket links#60113
Conversation
… links The "Open in Slack" link on a slack-channeled support ticket previously pointed at https://app.slack.com/client/<team>/<channel>/thread/<channel>-<ts>, which forces the browser web client and does not deep-link into the Slack desktop or mobile app. Switch to the canonical permalink format https://<workspace>.slack.com/archives/<channel>/p<ts> so the Slack apps intercept it and open the thread directly. The new format requires the workspace subdomain, which is not part of the OAuth response. Fetch it via team.info during the OAuth callback and store it on TeamConversationsSlackConfig. Expose it through the ticket serializer via a request-scoped lookup (one query per request, not N+1). The frontend helper falls back to the old app.slack.com URL when the domain is missing, so connections that predate this change keep working until the next reconnect. Generated-By: PostHog Code Task-Id: c2e92aa2-0549-42d7-9834-72585001b9f1
…ck.com permalink Per review feedback: app.slack.com/archives/<channel>/p<ts> works as well as the workspace-subdomain permalink, so the backend additions (slack_team_domain column, team.info OAuth fetch, serializer field, request-scoped lookup, tests) are all unnecessary. Revert them and keep only the frontend URL format change. Generated-By: PostHog Code Task-Id: c2e92aa2-0549-42d7-9834-72585001b9f1
|
Size Change: 0 B Total Size: 80.1 MB ℹ️ View Unchanged
|
Prompt To Fix All With AIFix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
products/conversations/frontend/scenes/ticket/SupportTicketScene.tsx:274
**`app.slack.com/archives/…` may not deep-link into the Slack desktop app**
The PR description explicitly states that only the workspace-specific canonical format `https://<workspace>.slack.com/archives/<channel>/p<ts>` is intercepted by the Slack desktop/mobile apps, and that the workspace subdomain "is the only piece we are missing." Slack's URL-handler registration is keyed on `*.slack.com` subdomains; `app.slack.com` is the generic web-client host and may not be caught by the OS-level handler that would open the desktop app. Verified with Slack's deep-link documentation: the `slack://` scheme or workspace-specific subdomains are what reliably trigger the native app — `app.slack.com` URLs typically remain in the browser.
This change improves the `/client/` → `/archives/` path (better web-client navigation) but the stated goal of deep-linking into the Slack app requires the workspace subdomain, which the PR description planned to surface via `slack_team_domain` but that backend addition is absent from this diff.
Reviews (1): Last reviewed commit: "refactor(conversations): drop workspace-..." | Re-trigger Greptile |
| <span className="text-muted-alt">Slack thread</span> | ||
| <Link | ||
| to={`https://app.slack.com/client/${ticket.slack_team_id}/${ticket.slack_channel_id}/thread/${ticket.slack_channel_id}-${ticket.slack_thread_ts.replace('.', '')}`} | ||
| to={`https://app.slack.com/archives/${ticket.slack_channel_id}/p${ticket.slack_thread_ts.replace('.', '')}`} |
There was a problem hiding this comment.
app.slack.com/archives/… may not deep-link into the Slack desktop app
The PR description explicitly states that only the workspace-specific canonical format https://<workspace>.slack.com/archives/<channel>/p<ts> is intercepted by the Slack desktop/mobile apps, and that the workspace subdomain "is the only piece we are missing." Slack's URL-handler registration is keyed on *.slack.com subdomains; app.slack.com is the generic web-client host and may not be caught by the OS-level handler that would open the desktop app. Verified with Slack's deep-link documentation: the slack:// scheme or workspace-specific subdomains are what reliably trigger the native app — app.slack.com URLs typically remain in the browser.
This change improves the /client/ → /archives/ path (better web-client navigation) but the stated goal of deep-linking into the Slack app requires the workspace subdomain, which the PR description planned to surface via slack_team_domain but that backend addition is absent from this diff.
Prompt To Fix With AI
This is a comment left during a code review.
Path: products/conversations/frontend/scenes/ticket/SupportTicketScene.tsx
Line: 274
Comment:
**`app.slack.com/archives/…` may not deep-link into the Slack desktop app**
The PR description explicitly states that only the workspace-specific canonical format `https://<workspace>.slack.com/archives/<channel>/p<ts>` is intercepted by the Slack desktop/mobile apps, and that the workspace subdomain "is the only piece we are missing." Slack's URL-handler registration is keyed on `*.slack.com` subdomains; `app.slack.com` is the generic web-client host and may not be caught by the OS-level handler that would open the desktop app. Verified with Slack's deep-link documentation: the `slack://` scheme or workspace-specific subdomains are what reliably trigger the native app — `app.slack.com` URLs typically remain in the browser.
This change improves the `/client/` → `/archives/` path (better web-client navigation) but the stated goal of deep-linking into the Slack app requires the workspace subdomain, which the PR description planned to surface via `slack_team_domain` but that backend addition is absent from this diff.
How can I resolve this? If you propose a fix, please make it concise.
Problem
When a Conversations support ticket is opened from a Slack thread, the "Open in Slack" link points at:
That URL only opens in the Slack web client and does not deep-link into the desktop or mobile Slack app — clicking it from PostHog drops users into the browser even when Slack is installed, and the routing depends on whether the viewer is signed in to the right workspace in the browser. Multiple agents have reported being unable to navigate from the ticket to the actual Slack thread.
The canonical message-permalink format Slack uses on its own UI is:
This format is intercepted by the Slack apps and deep-links straight into the thread. The only piece we are missing is the workspace subdomain (the
<workspace>part).Changes
slack_team_domaintoTeamConversationsSlackConfig(nullableCharField, non-blocking migration0037).team.infoto resolve the workspace subdomain and persist it next to the bot token. Failure to fetch is logged but non-fatal — the rest of the flow continues so a transient Slack outage cannot break onboarding.transaction.atomic()block to avoid holding a row lock open during the Slack HTTP call.slack_team_domainonTicketSerializeras aSerializerMethodField. The viewset overridesget_serializer_context()to do exactly one config lookup per request, so list views remain O(1) regardless of how many Slack tickets are in the page.SupportTicketScenewith a smallbuildSlackThreadUrlhelper:app.slack.com/clientURL — same behaviour as today, so nothing regresses until the user reconnects.https://slack.com/archives/...only when neither domain nor team id is set (should never happen for Slack-channeled tickets).Existing OAuth integrations will pick up the domain the next time they reconnect; we deliberately did not add a backfill migration since this only affects a small number of connections today and a re-OAuth is one click.
How did you test this code?
I'm an agent — I did not click through the UI. Automated coverage I added:
test_slack_token_storage.py: persistence/clearing ofslack_team_domainthroughsave_supporthog_slack_tokenandclear_supporthog_slack_token, including the "domain explicitly nulled on overwrite" path.test_tickets.py: three new cases onTicketSerializer— Slack ticket with domain configured, Slack ticket with no domain configured (must serialize as null), and non-Slack ticket (must always serialize null, never accidentally inherit the workspace domain).I did not run the test suite locally (no Python venv in this environment); relying on CI.
The OpenAPI generated types in
products/conversations/frontend/generated/are intentionally not regenerated in this commit — the CI auto-commit step (build:openapi+scaffold-yaml --sync-all) will produce them on the PR branch.Publish to changelog?
no
Docs update
No docs changes.
🤖 Agent context
slack.com/archives/...URL without the subdomain — rejected because the Slack apps do not deep-link without the workspace subdomain.slack://deep links — rejected because they only work when the desktop app is installed, with no usable web fallback.posthog/temporal/ai/slack_conversation.py/ee.Conversation.slack_workspace_domainfor the Max integration, so the convention exists and is well-understood.slack_team_domainon eachTicketrow (denormalized snapshot) but decided against it — domain is invariant per workspace, putting it on the per-workspace config row keeps the schema clean and lets a future workspace rename propagate to all existing tickets.Created with PostHog Code