# Slack Request URLs Migration Plan (Marketplace Readiness)

Status: Draft  
Last Updated: 2026-03-02  
Primary Goal: Replace Slack Socket Mode with HTTP Request URLs and complete the installation/token architecture required for Slack Marketplace publication.

## 1. Problem Statement

The current Slack integration uses Socket Mode. Slack Marketplace public apps cannot use Socket Mode, so the app cannot be published publicly until inbound event delivery is migrated to Request URLs.

This migration must preserve current functionality:

1. DM responses.
2. Public/private channel `@mention` responses.
3. Slack-friendly link rendering in agent responses.
4. Queue-based, retry-safe processing for long-running research workflows.

## 2. Current State (Code Snapshot)

1. Socket Mode runtime:
   - `microservices/slack_connector/main.py`
   - Uses Bolt `SocketModeHandler`.
2. Worker dyno starts Slack connector:
   - `scripts/run_worker_with_slack_connector.sh`
   - `Procfile` worker command.
3. Slack HTTP routes currently include connect flow only:
   - `app/slack/routes.py` (`/slack/connect`)
4. Ingress filtering + idempotent enqueue already exist:
   - `app/slack/gateway.py` (`should_process_event`, `enqueue_slack_event`)
5. Outbound posting + link normalization exist:
   - `app/slack/tasks.py`
6. Slack Web API token model is global singleton:
   - `app/slack/slack_api.py` uses `SLACK_BOT_TOKEN` env var.
7. Workspace linkage model exists but does not store Slack bot installation tokens:
   - `sixseeds_shared/models.py` (`SlackWorkspace`)

## 3. Target State

1. Slack sends all events to `POST /slack/events` over HTTPS.
2. Web app verifies Slack signatures and responds in under 3 seconds.
3. Event handler immediately enqueues work and returns `200`.
4. Worker processes queued jobs and posts responses as today.
5. Slack installation is OAuth-based for each workspace.
6. Bot tokens are stored per workspace installation (encrypted at rest).
7. All Slack Web API calls resolve token by workspace/team, not global env token.

## 4. Scope

In scope:

1. Request URL ingress.
2. Socket Mode runtime removal from production path.
3. OAuth installation flow and token persistence.
4. Workspace-scoped Slack client/token resolution.
5. Testing, rollout, rollback, and operations runbook updates.

Out of scope:

1. Major redesign of Slack conversation UX.
2. Changes to core FishDog study orchestration logic.
3. RBAC/role restrictions within Slack commands.

## 5. Delivery Strategy (Phased)

### Phase 0: Pre-migration Guardrails

Tasks:

1. Add transport flag: `SLACK_TRANSPORT=http|socket`.
2. Define production Request URL and OAuth redirect URL.
3. Confirm final Slack scope list and event subscriptions.
4. Confirm rollback procedure before production cutover.

Acceptance criteria:

1. Written cutover checklist approved.
2. Staging/prod URLs and secrets confirmed.

### Phase 1: Add HTTP Events Endpoint

Tasks:

1. Add `POST /slack/events` route in `app/slack/routes.py` or a dedicated `app/slack/events.py`.
2. Verify Slack request signature and timestamp (`X-Slack-Signature`, `X-Slack-Request-Timestamp`).
3. Handle `url_verification` challenge payload.
4. Parse `event_callback` and call existing:
   - `should_process_event(...)`
   - `enqueue_slack_event(...)`
5. Return fast `200` after enqueue.
6. Keep dedupe behavior based on `event_id`.

Suggested implementation pattern:

1. Keep Slack-specific ingress logic in a small module (`app/slack/events.py`).
2. Reuse gateway enqueue path to avoid duplicating idempotency logic.

Acceptance criteria:

1. Slack URL verification succeeds in staging.
2. DM and channel events are received via HTTP ingress and queued.
3. No synchronous long-running work occurs in the request handler.

### Phase 2: Production Runtime Cutover

Tasks:

1. Remove connector startup from worker process:
   - update `Procfile`
   - stop using `scripts/run_worker_with_slack_connector.sh` for production.
2. Keep Socket Mode code behind `SLACK_TRANSPORT=socket` for temporary rollback.
3. Disable Socket Mode in Slack app settings after staging validation.
4. Enable Event Subscriptions with Request URL in Slack app settings.

Acceptance criteria:

1. Production ingress works without `SocketModeHandler`.
2. Worker only processes queue jobs.
3. Event success rate and reply behavior meet baseline.

### Phase 3: OAuth Installation + Per-Workspace Token Storage

Tasks:

1. Add installation routes:
   - `/slack/install`
   - `/slack/oauth/callback`
2. Implement OAuth state/nonce handling.
3. Exchange auth code using `oauth.v2.access`.
4. Persist installation metadata:
   - `team_id`
   - encrypted `bot_token`
   - `bot_user_id`
   - granted scopes
   - installer user id
   - timestamps
5. Add a storage model:
   - preferred: new `slack_installations` table
   - alternative: extend `slack_workspaces` with installation fields
6. Add token resolver:
   - `get_slack_client_for_workspace(workspace_external_id|workspace_id)`
7. Refactor Slack Web API calls to use workspace-scoped tokens.
8. Add temporary compatibility fallback to `SLACK_BOT_TOKEN` for legacy workspaces during migration window.

Acceptance criteria:

1. Multiple workspaces can install app independently.
2. Each workspace uses its own token for reads/writes.
3. No critical runtime path requires singleton global token.

### Phase 4: Marketplace Readiness Hardening

Tasks:

1. Trim scopes to least privilege required.
2. Ensure app responses in DM, public channels, private channels remain correct.
3. Confirm channel auto-join/retry behavior and mention handling remain intact.
4. Finalize support docs for Slack review.

Acceptance criteria:

1. Scope list and features are aligned.
2. App behavior is stable after transport/auth changes.

## 6. Code-Level Work Breakdown

Primary files expected to change:

1. `app/slack/routes.py` (add events + OAuth endpoints)
2. `app/slack/gateway.py` (reuse, minimal changes)
3. `app/slack/slack_api.py` (workspace-scoped client resolution)
4. `app/slack/tasks.py` (ensure outbound calls use scoped client)
5. `sixseeds_shared/models.py` (installation model if using ORM model changes)
6. `migrations/versions/<revision>.py` (schema migration)
7. `Procfile` (remove socket connector runtime path)
8. `scripts/run_worker_with_slack_connector.sh` (deprecate or retain only for rollback/testing)
9. `docs/claude_code_instructions/slack_ditto_integration_runbook.md` (runtime setup update)

New modules likely needed:

1. `app/slack/events.py` (HTTP ingress handler)
2. `app/slack/oauth.py` (OAuth flow + storage)

## 7. Testing Requirements

### Unit Tests (mandatory)

1. Valid `url_verification` challenge returns expected payload.
2. Invalid Slack signature is rejected.
3. Stale timestamp/replay window is rejected.
4. Valid `event_callback` enqueues exactly one job.
5. Duplicate `event_id` does not enqueue duplicate work.
6. Retry headers (`X-Slack-Retry-Num`) do not create duplicate processing.
7. OAuth state mismatch is rejected.
8. OAuth callback success persists installation/token metadata.
9. Workspace-scoped Slack client resolves correct token.
10. Outbound post path uses workspace token.
11. Existing link normalization tests continue passing.
12. Existing mention routing tests continue passing.

### Integration Tests (mandatory)

1. Signed HTTP event payload reaches `/slack/events` and enters queue.
2. Worker consumes queued event and posts Slack response using scoped token.
3. OAuth callback integration with mocked Slack token exchange.
4. Multi-workspace path validates token isolation (workspace A token is never used for workspace B).
5. Migration fallback path works for legacy row without installation token during transition window.

### Manual Staging UAT (mandatory)

1. DM: user message receives response.
2. Public channel: `@AppName` mention receives response.
3. Private channel: `@AppName` mention receives response when app is invited.
4. Links in responses are clickable for:
   - bare URL
   - markdown link
   - HTML anchor source text
5. Threading is preserved (`thread_ts` behavior).
6. Public channel auto-join/retry works when first post returns `not_in_channel`.
7. Unlinked workspace gets clear guidance.
8. OAuth install and reinstall work end-to-end.

### Non-functional validation (mandatory)

1. `POST /slack/events` p95 latency under expected load remains below 1 second.
2. Endpoint never exceeds Slack 3-second ack requirement.
3. Error rate and retry rate are monitored for 24h after cutover.
4. Logs include `event_id`, team/workspace id, enqueue status, and delivery outcome.

## 8. Observability and Alerting

Minimum dashboards/alerts:

1. Event ingress status counts by outcome (`queued`, `duplicate`, `queue_failed`, `release_blocked`).
2. Enqueue failure alert.
3. Reply delivery failure alert.
4. Signature verification failure rate alert.
5. Queue lag alert for Slack queue.

## 9. Deployment Plan

### Staging

1. Deploy Phase 1 code with HTTP ingress enabled.
2. Configure Slack staging app:
   - Event Subscriptions ON
   - Request URL = `https://<staging-domain>/slack/events`
   - Socket Mode OFF
3. Run full unit + integration + manual UAT checklist.

### Production

1. Deploy code with rollback flag support.
2. Update Slack production app Request URL.
3. Disable Socket Mode in production app settings.
4. Monitor for 24 hours.
5. Proceed to OAuth/per-workspace token rollout if not already deployed.

## 10. Rollback Plan

1. Re-enable Socket Mode in Slack app config.
2. Set `SLACK_TRANSPORT=socket`.
3. Restore connector runtime process path if needed.
4. Keep schema changes backward-compatible to avoid emergency data migration during rollback.

## 11. Definition of Done

All must be true:

1. Socket Mode no longer required in production.
2. Slack events are ingested via Request URL.
3. Public/private/DM mention behavior works.
4. Link rendering remains correct in Slack.
5. OAuth installation and per-workspace token model are implemented.
6. Automated and manual test matrices are completed and recorded.
7. Runbook and operational docs are updated.

## 12. References

1. https://docs.slack.dev/apis/events-api/
2. https://docs.slack.dev/apis/events-api/using-http-request-urls/
3. https://docs.slack.dev/apis/events-api/using-socket-mode/
4. https://docs.slack.dev/authentication/verifying-requests-from-slack/
5. https://docs.slack.dev/authentication/installing-with-oauth/
6. https://docs.slack.dev/app-management/distribution/

## 13. Suggested Execution Package (PR Breakdown)

PR 1: HTTP ingress migration

1. Add `/slack/events` route.
2. Add signature verification + URL verification challenge handling.
3. Reuse gateway enqueue flow.
4. Add endpoint unit + integration tests.

PR 2: runtime cutover

1. Remove production dependency on Socket Mode worker startup.
2. Add transport flag rollback support.
3. Update runbook and deployment checklist.

PR 3: OAuth + per-workspace token architecture

1. Add install/callback routes.
2. Add installation storage and migration.
3. Refactor Slack client resolution to workspace-scoped tokens.
4. Add OAuth/token resolution tests.

PR 4: hardening + Marketplace preparation

1. Final scope/event subscription validation.
2. Full staging UAT pass and observability checks.
3. Final documentation and handoff.
