Design and scaffold: qbit-slack (per-user, multi-tenant Slack, delivery destinations) #1

Merged
KofTwentyTwo merged 2 commits from feature/spec-and-scaffold into develop 2026-10-14 16:02:21 +00:00
KofTwentyTwo commented 2026-10-14 15:59:59 +00:00 (Migrated from github.com)

Spec PR for qbit-slack, plus the repository scaffold.

Design: docs/DESIGN.md. Owner decisions (2026-10-14): all recommendations accepted (standing approval).

Summary

  • A core messaging provider (slack) and a core delivery destination (slack). Callers use core only: SendMessageAction or DeliverOutputAction.
  • Tied to the signed-in user, and multi-tenant safe.
    • Users connect Slack themselves with OAuth, and tenant admins install the bot for their own organization.
    • Every message has an owner, and is authorized as that owner when it's queued and again when it's sent.
    • Membership is checked with conversations.members, and there's never a fallback to another token.
    • Tokens are AES-GCM encrypted, bound to their row, write-only and HIDDEN.
    • The spec requires a test with two tenants and two workspaces.
  • Durable outbox.
    • Claim, lease and retry, with Retry-After handling.
    • Exactly-once posting: each post carries Slack message metadata, so a crashed runner's post is found instead of posted again.
    • Idempotency keys and sendOnce serve as the jobs_effect primitive.
  • Public SlackApi, which mirrors EmailApi. Readiness, and a health check.
  • Output delivery. Process results, jobs, scheduled reports and jobs, exports, saved views and assistant tasks can deliver to a Slack DM or channel. Pickers show only what the user's own connection can see. Large outputs are uploaded as files, or sent as a link.
    • The core SPI is specified separately in QRun-IO/qqq (docs/specs/OUTPUT-DELIVERY.md, a follow-up PR).
  • Routing. The single notify call stays core QAlerts.notify. The fan-out stays in qbit-alerts, which gets a Slack column per category.
    • This supersedes the 2026-10-13 decision that Slack is "never per user".
  • PHI and PII never go to Slack. Exports are blocked, or sent without the restricted columns. There's a canary test.
  • Phase 2: signed interactivity (Approve and Acknowledge) that runs as the clicking user, plus the Events API for revocations.
  • Owner steps (section 17):
    • create the Slack app from docs/slack-app-manifest.yaml;
    • seed four write-only Infisical keys in /kof22-website-slack (a Praetor PR);
    • add an ExternalSecret;
    • click "Install for my organization".

Scaffold

  • Coordinates com.kingsrook.qbits:qbit-slack.
  • qbit-build-parent 2.1.1, with guardrails enforced.
  • qqq-orb 0.6.9.
  • QQQ 4.1.0-RC.6.
  • Checkstyle and the JaCoCo gate.
  • Community files, the wrapper and the release-rc workflow are copied from qbit-email.
  • ./mvnw verify passes locally (guardrails G1, G3 and G4 pass).

🤖 Generated with Claude Code

Spec PR for qbit-slack, plus the repository scaffold. **Design:** `docs/DESIGN.md`. Owner decisions (2026-10-14): all recommendations accepted (standing approval). ## Summary - **A core messaging provider** (`slack`) and **a core delivery destination** (`slack`). Callers use core only: `SendMessageAction` or `DeliverOutputAction`. - **Tied to the signed-in user, and multi-tenant safe.** - Users connect Slack themselves with OAuth, and tenant admins install the bot for their own organization. - Every message has an owner, and is authorized as that owner when it's queued and again when it's sent. - Membership is checked with `conversations.members`, and there's never a fallback to another token. - Tokens are AES-GCM encrypted, bound to their row, write-only and HIDDEN. - The spec requires a test with two tenants and two workspaces. - **Durable outbox.** - Claim, lease and retry, with `Retry-After` handling. - Exactly-once posting: each post carries Slack message metadata, so a crashed runner's post is found instead of posted again. - Idempotency keys and `sendOnce` serve as the jobs_effect primitive. - **Public `SlackApi`**, which mirrors `EmailApi`. Readiness, and a health check. - **Output delivery.** Process results, jobs, scheduled reports and jobs, exports, saved views and assistant tasks can deliver to a Slack DM or channel. Pickers show only what the user's own connection can see. Large outputs are uploaded as files, or sent as a link. - The core SPI is specified separately in QRun-IO/qqq (`docs/specs/OUTPUT-DELIVERY.md`, a follow-up PR). - **Routing.** The single notify call stays core `QAlerts.notify`. The fan-out stays in qbit-alerts, which gets a Slack column per category. - This supersedes the 2026-10-13 decision that Slack is "never per user". - **PHI and PII never go to Slack.** Exports are blocked, or sent without the restricted columns. There's a canary test. - **Phase 2:** signed interactivity (Approve and Acknowledge) that runs as the clicking user, plus the Events API for revocations. - **Owner steps (section 17):** - create the Slack app from `docs/slack-app-manifest.yaml`; - seed four write-only Infisical keys in `/kof22-website-slack` (a Praetor PR); - add an ExternalSecret; - click "Install for my organization". ## Scaffold - Coordinates `com.kingsrook.qbits:qbit-slack`. - `qbit-build-parent` 2.1.1, with guardrails enforced. - `qqq-orb` 0.6.9. - QQQ 4.1.0-RC.6. - Checkstyle and the JaCoCo gate. - Community files, the wrapper and the `release-rc` workflow are copied from qbit-email. - `./mvnw verify` passes locally (guardrails G1, G3 and G4 pass). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.