Skip to content

feat(api): /chat Slack workspace redirect (closes #79)#100

Merged
themightychris merged 3 commits into
mainfrom
feat/chat-redirect
May 30, 2026
Merged

feat(api): /chat Slack workspace redirect (closes #79)#100
themightychris merged 3 commits into
mainfrom
feat/chat-redirect

Conversation

@themightychris
Copy link
Copy Markdown
Member

Summary

  • GET /chat 302s to https://<SLACK_TEAM_HOST>/
  • GET /chat?channel=<name> 302s to /channels/<name> when name matches /^[a-z0-9][a-z0-9_-]{0,40}$/ (same regex as Project.chatChannel — protects against open-redirect / path injection)
  • Empty or malformed channel falls back to the workspace root with a warn log; no 4xx per spec ("degrade quietly")
  • Cache-Control: no-cache + 302 (not 301) so the destination can flip later without browser caches sticking

Closes #79. Implements specs/screens/chat.md.

Test plan

  • 9 new tests in apps/api/tests/chat-redirect.test.ts — no-channel, valid channel, hyphens/underscores OK, empty channel → root, uppercase → root, slash-injection → root, over-long → root, leading-hyphen → root, /api/chat 404s
  • 319 API + 30 web + 69 shared tests green; npm run type-check && npm run lint clean

🤖 Generated with Claude Code

themightychris and others added 3 commits May 30, 2026 08:56
/chat is spec'd in specs/screens/chat.md as a 302 to the Code for Philly
Slack workspace, with optional ?channel=foo deep-linking. The route
doesn't exist today — every "Open Slack" link across the SPA falls
through to the SPA catch-all. Plan covers route, channel validation
(reusing Project.chatChannel regex for open-redirect safety), tests.

Closes #79.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GET /chat 302s to https://<SLACK_TEAM_HOST>/ and
GET /chat?channel=<name> 302s to /channels/<name>. Empty or
malformed channels fall back to the workspace root with a warn log
(per spec: degrade quietly rather than 4xx). Cache-Control: no-cache
so the destination can flip without browser caches sticking; 302 (not
301) for the same reason.

Channel validation reuses the Project.chatChannel regex
(/^[a-z0-9][a-z0-9_-]{0,40}$/) — same shape the data already enforces,
and tight enough that the channel can't smuggle a slash, protocol, or
relative-path traversal into the redirect URL. The hardcoded host comes
from fastify.config.SLACK_TEAM_HOST, never the request.

Per specs/screens/chat.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
All validation checkboxes ticked. Notes covers the channel-regex hoist
trade-off (duplicate literal rather than Zod-internals plumbing), the
Fastify querystring typing pattern, and the /api/chat 404 assertion.
Follow-ups: typeahead is None (no real ask); per-channel analytics
deferred to next observability pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@themightychris themightychris merged commit 0ab6961 into main May 30, 2026
1 check passed
@themightychris themightychris deleted the feat/chat-redirect branch May 30, 2026 13:18
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.

api: /chat and /chat?channel= Slack-redirect routes

1 participant