65 Commits
Author SHA1 Message Date
james.maes 312e95cc17 Merge pull request 'fix(connect): a Continue to Slack link, a landing page that exists and a plain refusal' (#37) from fix/connect-continue-to-slack into develop
maven / build (push) Successful in 1m26s
build / maven (push) Successful in 1m26s
2026-11-11 12:32:16 +00:00
james.maesandClaude Fable 5.2 80bea0f931 fix(connect): a Continue to Slack link, a landing page that exists and a plain refusal
maven / build (push) Successful in 1m35s
build / maven (push) Successful in 1m35s
Install for my organization and Connect Slack on the Connections table
ended on an empty screen with only a Return button. The screen declared
a view field (authorizeUrl) but no component, and a frontend step shows
only the components it declares. The screen is now an HTML component:
one sentence about what happens, a Continue to Slack link to the consent
page (same tab, so Slack can return the browser) and the lifetime of the
link, read from SlackOAuthState.LIFETIME_SECONDS (10 minutes).

After Slack, the callback redirected to /preferences?section=slack,
which the host UI does not serve. It returns to
/app/preferences?section=slack with &result=connected or &error=<code>.

Connecting in an environment without the public URL or the Slack app
secrets failed with "IllegalArgumentException (Slack public URL is
required)" or "Slack secret unavailable". It is refused before any state
is issued with a user-facing message that says Slack is not set up in
this environment, which of the two is missing, and the names of the
missing environment variables, never a value.

The Preferences action still answers with the authorize address as the
whole message: core has no redirect field on an action result.
qqq-frontend-next opens a message that is only an https address.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-11 06:29:49 -06:00
james.maes 2508c6b93c Merge pull request 'build(deps): align with Gitea registry (parent 2.2.1, QQQ 4.1.0-RC.26)' (#34) from deps/align-gitea into develop
maven / build (push) Successful in 1m49s
build / maven (push) Successful in 1m49s
2026-11-07 19:50:51 +00:00
james.maesandClaude Opus 5.5 cd3205e249 build(deps): align with Gitea registry (parent 2.2.1, QQQ 4.1.0-RC.26)
maven / build (push) Failing after 4m10s
build / maven (push) Failing after 4m10s
pom.xml: parent -> 2.2.1
pom.xml: qqq.snapshot.version: 4.1.0-RC.7 -> 4.1.0-RC.26
pom.xml: qqq-frontend-next: 1.0.0-RC.19 -> 1.0.0-RC.38
pom.xml: added qqq.version=4.1.0-RC.26 (parent BOM import)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-07 18:09:23 +00:00
james.maes 26aac94b52 Merge pull request 'ci: pin shared workflow to v1' (#33) from ci/pin-v1-develop into develop
QRun-IO/ci-policy: ci / fork-guard (push) Skipped
QRun-IO/ci-policy: native / fork-deny (push) Skipped
QRun-IO/ci-policy: native / dotnet-0 (push) Skipped
QRun-IO/ci-policy: ci / Scoped workflow [workflow 1e25bb5a243dfdcd95d4b9a4f780200ff8c8778a] (push) Successful in 13s
QRun-IO/ci-policy: ci / gradle-1 (push) Skipped
QRun-IO/ci-policy: ci / head-profile (push) Skipped
QRun-IO/ci-policy: ci / repository-policy (push) Skipped
QRun-IO/ci-policy: ci / application-template-0 (push) Skipped
QRun-IO/ci-policy: ci / java-core-2-head (push) Skipped
QRun-IO/ci-policy: ci / java-docker-3 (push) Skipped
QRun-IO/ci-policy: ci / java-docker-3-head (push) Skipped
QRun-IO/ci-policy: ci / java-docker-4 (push) Skipped
QRun-IO/ci-policy: ci / java-frontend-browser-5 (push) Skipped
QRun-IO/ci-policy: ci / java-maven-6 (push) Skipped
QRun-IO/ci-policy: ci / java-maven-6-head (push) Skipped
QRun-IO/ci-policy: ci / java-maven-7 (push) Skipped
QRun-IO/ci-policy: ci / java-maven-7-head (push) Skipped
QRun-IO/ci-policy: ci / node-8 (push) Skipped
QRun-IO/ci-policy: ci / node-9 (push) Skipped
QRun-IO/ci-policy: ci / node-10 (push) Skipped
QRun-IO/ci-policy: ci / node-playwright-11 (push) Skipped
QRun-IO/ci-policy: ci / repository-policy-12 (push) Skipped
QRun-IO/ci-policy: ci / source-config-13 (push) Skipped
QRun-IO/ci-policy: ci / source-config-14 (push) Skipped
QRun-IO/ci-policy: ci / android-0 (push) Skipped
QRun-IO/ci-policy: ci / original-business (push) Skipped
QRun-IO/ci-policy: ci / original-mcp (push) Skipped
QRun-IO/ci-policy: ci / original-voyage (push) Skipped
QRun-IO/ci-policy: ci / original-cli (push) Skipped
QRun-IO/ci-policy: ci / not-enrolled (push) Skipped
QRun-IO/ci-policy: ci / shared-pipeline (push) Skipped
QRun-IO/ci-policy: native / native-result (push) Successful in 10s
QRun-IO/ci-policy: ci / ci-result (push) Successful in 13s
maven / build (push) Successful in 4m42s
build / maven (push) Successful in 4m43s
2026-11-06 16:10:48 +00:00
james.maesandClaude Opus 5.5 7804c6aed7 ci: pin shared workflow to v1
QRun-IO/ci-policy: native / fork-deny (pull_request) Skipped
QRun-IO/ci-policy: native / dotnet-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / Scoped workflow [workflow 1e25bb5a243dfdcd95d4b9a4f780200ff8c8778a] (pull_request) Successful in 8s
QRun-IO/ci-policy: native / native-result (pull_request) Successful in 6s
QRun-IO/ci-policy: ci / head-profile (pull_request) Skipped
QRun-IO/ci-policy: ci / repository-policy (pull_request) Skipped
QRun-IO/ci-policy: ci / application-template-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / gradle-1 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-core-2-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-3 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-3-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-4 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-frontend-browser-5 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-6 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-6-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-7 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-7-head (pull_request) Skipped
QRun-IO/ci-policy: ci / node-8 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-9 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-10 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-playwright-11 (pull_request) Skipped
QRun-IO/ci-policy: ci / repository-policy-12 (pull_request) Skipped
QRun-IO/ci-policy: ci / source-config-13 (pull_request) Skipped
QRun-IO/ci-policy: ci / source-config-14 (pull_request) Skipped
QRun-IO/ci-policy: ci / android-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / original-business (pull_request) Skipped
QRun-IO/ci-policy: ci / original-mcp (pull_request) Skipped
QRun-IO/ci-policy: ci / original-voyage (pull_request) Skipped
QRun-IO/ci-policy: ci / original-cli (pull_request) Skipped
QRun-IO/ci-policy: ci / not-enrolled (pull_request) Skipped
QRun-IO/ci-policy: ci / shared-pipeline (pull_request) Skipped
QRun-IO/ci-policy: ci / ci-result (pull_request) Successful in 7s
maven / build (push) Successful in 4m1s
build / maven (push) Successful in 4m2s
QRun-IO/ci-policy: ci / fork-guard (pull_request) Skipped
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 14:13:59 +00:00
james.maes e1f362b22c Merge pull request 'ci: use shared ci-workflows Maven workflow' (#32) from ci/ci-workflows into develop
QRun-IO/ci-policy: ci / fork-guard (push) Skipped
QRun-IO/ci-policy: native / fork-deny (push) Skipped
QRun-IO/ci-policy: native / dotnet-0 (push) Skipped
QRun-IO/ci-policy: ci / Scoped workflow [workflow d20a578c7d818bc7ca32a2ac2c675da4e4f27385] (push) Successful in 5s
QRun-IO/ci-policy: native / native-result (push) Successful in 5s
QRun-IO/ci-policy: ci / head-profile (push) Skipped
QRun-IO/ci-policy: ci / repository-policy (push) Skipped
QRun-IO/ci-policy: ci / application-template-0 (push) Skipped
QRun-IO/ci-policy: ci / gradle-1 (push) Skipped
QRun-IO/ci-policy: ci / java-core-2-head (push) Skipped
QRun-IO/ci-policy: ci / java-docker-3 (push) Skipped
QRun-IO/ci-policy: ci / java-docker-3-head (push) Skipped
QRun-IO/ci-policy: ci / java-docker-4 (push) Skipped
QRun-IO/ci-policy: ci / java-frontend-browser-5 (push) Skipped
QRun-IO/ci-policy: ci / java-maven-6 (push) Skipped
QRun-IO/ci-policy: ci / java-maven-6-head (push) Skipped
QRun-IO/ci-policy: ci / java-maven-7 (push) Skipped
QRun-IO/ci-policy: ci / java-maven-7-head (push) Skipped
QRun-IO/ci-policy: ci / node-8 (push) Skipped
QRun-IO/ci-policy: ci / node-9 (push) Skipped
QRun-IO/ci-policy: ci / node-10 (push) Skipped
QRun-IO/ci-policy: ci / node-playwright-11 (push) Skipped
QRun-IO/ci-policy: ci / repository-policy-12 (push) Skipped
QRun-IO/ci-policy: ci / source-config-13 (push) Skipped
QRun-IO/ci-policy: ci / source-config-14 (push) Skipped
QRun-IO/ci-policy: ci / android-0 (push) Skipped
QRun-IO/ci-policy: ci / original-business (push) Skipped
QRun-IO/ci-policy: ci / original-mcp (push) Skipped
QRun-IO/ci-policy: ci / original-voyage (push) Skipped
QRun-IO/ci-policy: ci / original-cli (push) Skipped
QRun-IO/ci-policy: ci / not-enrolled (push) Skipped
QRun-IO/ci-policy: ci / shared-pipeline (push) Skipped
QRun-IO/ci-policy: ci / ci-result (push) Successful in 4s
maven / build (push) Successful in 2m47s
build / maven (push) Successful in 2m47s
2026-11-05 23:18:12 +00:00
james.maesandClaude Opus 5.5 48a2387ac6 ci: use shared ci-workflows Maven workflow
maven / build (push) Failing after 2s
build / maven (push) Failing after 1s
QRun-IO/ci-policy: ci / fork-guard (pull_request) Skipped
QRun-IO/ci-policy: native / fork-deny (pull_request) Skipped
QRun-IO/ci-policy: native / dotnet-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / Scoped workflow [workflow 1b3648d9421543350067e95e54959dfb471b26d5] (pull_request) Failing after 1s
QRun-IO/ci-policy: native / native-result (pull_request) Failing after 1s
QRun-IO/ci-policy: ci / head-profile (pull_request) Skipped
QRun-IO/ci-policy: ci / repository-policy (pull_request) Skipped
QRun-IO/ci-policy: ci / application-template-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / gradle-1 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-core-2-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-3 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-3-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-4 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-frontend-browser-5 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-6 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-6-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-7 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-7-head (pull_request) Skipped
QRun-IO/ci-policy: ci / node-8 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-9 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-10 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-playwright-11 (pull_request) Skipped
QRun-IO/ci-policy: ci / repository-policy-12 (pull_request) Skipped
QRun-IO/ci-policy: ci / source-config-13 (pull_request) Skipped
QRun-IO/ci-policy: ci / source-config-14 (pull_request) Skipped
QRun-IO/ci-policy: ci / android-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / original-business (pull_request) Skipped
QRun-IO/ci-policy: ci / original-mcp (pull_request) Skipped
QRun-IO/ci-policy: ci / original-voyage (pull_request) Skipped
QRun-IO/ci-policy: ci / original-cli (pull_request) Skipped
QRun-IO/ci-policy: ci / not-enrolled (pull_request) Skipped
QRun-IO/ci-policy: ci / shared-pipeline (pull_request) Skipped
QRun-IO/ci-policy: ci / ci-result (pull_request) Failing after 7s
Replace the platform-ci release callers with one caller of
KofTwentyTwo/ci-workflows maven.yaml (qqq-orb port).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 22:08:36 +00:00
james.maesandCodex 33ba265215 ci: adopt managed orb 0.8 patch track (#26)
Co-authored-by: Codex <noreply@openai.com>
2026-10-21 15:28:28 -05:00
james.maesandCodex 7a0fd3762a ci: adopt shared orb 0.7.18 (#25)
Co-authored-by: Codex <noreply@openai.com>
2026-10-21 14:46:34 -05:00
james.maesandCodex 2682c2fa94 ci: adopt shared orb 0.7.17 (#24)
Co-authored-by: Codex <noreply@openai.com>
2026-10-21 14:16:09 -05:00
james.maesandCodex 42aaf3c9c8 ci: use the shared branch-aware CodeQL worker (#22)
Co-authored-by: Codex <noreply@openai.com>
2026-10-21 10:43:15 -05:00
james.maesandCodex a40eade67b ci: adopt central orb 0.7.12 and stable gates (#20)
Co-authored-by: Codex <noreply@openai.com>
2026-10-21 08:50:01 -05:00
james.maesandCodex f0b70d7da7 ci: centralize rc release completion in qqq orb (#18)
Co-authored-by: Codex <noreply@openai.com>
2026-10-21 02:23:37 -05:00
james.maesandCodex 4dcabdffed ci: adopt shared orb 0.7.11 (#17)
Co-authored-by: Codex <noreply@openai.com>
2026-10-21 00:57:21 -05:00
james.maes de09fc27e9 Merge pull request #16 from QRun-IO/feature/central-ci
ci: adopt shared QQQ orb 0.7.4
2026-10-20 19:33:40 -05:00
james.maesandCodex fb4ae6db07 ci: adopt central QQQ orb 0.7.4
Co-Authored-By: Codex <noreply@openai.com>
2026-10-20 19:26:57 -05:00
james.maes 2f7025ef28 Merge pull request #15 from QRun-IO/ci/release-rc-secrets-inherit
ci(release-rc): pass secrets so the shared workflow can sign the RC tag
2026-10-16 08:03:45 -05:00
james.maesandClaude Opus 5.5 33d993f414 ci(release-rc): pass secrets to the shared workflow so it can sign the RC tag
QRun-IO/.github#2 adds a tag-and-release job that signs vX with the
QRUN_TAG_SIGNING_KEY secret after Maven Central confirms the artifact.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 16:20:23 -05:00
james.maes 87a2218ef6 Merge pull request #14 from QRun-IO/fix/producer-version-from-build
fix: qbit metadata version comes from the build
2026-10-15 01:42:56 -05:00
james.maesandClaude Opus 5.5 56b6f48a7b fix: the qbit metadata version comes from the build, not a hardcoded constant
The producer read a literal version, so released artifacts reported a stale
or -SNAPSHOT version. qbit-slack.properties (version=${project.version}) is
Maven-filtered and the producer loads it; tests assert producer == bundle ==
artifact version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 01:33:09 -05:00
james.maes 80083044a8 Merge pull request #13 from QRun-IO/fix/health-not-configured
fix(health): unconfigured Slack is UNKNOWN, never DOWN
2026-10-14 23:57:11 -05:00
james.maesandClaude Opus 5.5 1811bbf211 fix(health): an unconfigured Slack app is UNKNOWN, never DOWN
With no SLACK_* secrets at all the app readiness check is NOT_CONFIGURED and
the health indicator reports UNKNOWN (HTTP 200) with configured=false, so an
optional, unset Slack integration can't fail a readiness probe (it took kof22's
probe down). Not-yet-checked is UNKNOWN too. Partial or invalid configuration
stays DOWN. Tests for all three.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 23:54:33 -05:00
james.maes 070e2c95d9 Merge pull request #12 from QRun-IO/fix/help-bundle-version
fix(help): help bundle version comes from the build, not a hardcoded SNAPSHOT
2026-10-14 22:37:20 -05:00
james.maesandClaude Opus 5.5 7f71fc0566 fix(help): the help bundle carries the artifact version (Maven-filtered) instead of a hardcoded SNAPSHOT
On release branches the bundle's version and the producer's differed, so the
bundle test that asserts they match failed, and released bundles recorded
SNAPSHOT as their provenance. help/*.yaml is now filtered:
version: ${project.version}.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 22:10:36 -05:00
james.maes 91b24cb986 Merge pull request #11 from QRun-IO/feature/help-bundle
feat(help): qbit-slack help bundle via QQQ help bundles, with coverage gate
2026-10-14 20:45:30 -05:00
james.maesandClaude Opus 5.5 36def54b8b feat(help): ship the qbit-slack help bundle through QQQ help bundles, with coverage gate
Host-neutral help (deployment-specific facts removed), registered with
HelpBundles, gated by HelpBundleAssertions. QQQ 4.1.0-RC.7.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 20:37:13 -05:00
james.maes c28210353e Merge pull request #10 from QRun-IO/fix/rc7-preferences
fix: start on QQQ 4.1.0-RC.7 (real user-preferences SPI; #1194 fields)
2026-10-14 19:51:17 -05:00
james.maesandClaude Opus 5.5 37524048ba refactor(bridge): core #1194 rich messaging fields on RC.7, drop the stand-in
The QBIT_SLACK provider declares its capabilities and returns status, message
id and reasons through core SendMessageOutput; idempotency keys and templates
come from SendMessageInput.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 19:48:26 -05:00
james.maesandClaude Opus 5.5 1ddbf470de fix(preferences): real core user-preferences SPI on QQQ 4.1.0-RC.7
RC.1-RC.3 failed to start on RC.7: the reflection adapter (written against the
#1162 stand-in) called a withSection signature RC.7 doesn't have. Replace it with
SlackPreferencesProvider on the real SPI (section, connections list, Connect,
Install, test message and Disconnect actions, read-only store), registered only
when the core classes exist. Startup test validates the instance on RC.7.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 19:48:26 -05:00
james.maes c1064601da Merge pull request #9 from QRun-IO/feature/tables-populated-defaults
feat: every slack table explains itself; channel status and group handle wired
2026-10-14 17:42:44 -05:00
james.maesandClaude Opus 5.5 d8063498a2 fix: only persist definitive channel answers; Check channels reporting; hostHelpIsKept
- 429, 5xx, timeouts and invalid_auth leave channel rows alone, stop the
  workspace loop and make the channels check a warning.
- Handle sync needs only usergroups:read.
- Check channels reports warnings and per-row errors; status fields are
  read-only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:26:20 -05:00
james.maesandClaude Opus 5.5 4bc330d96b feat: table help, channel status write-back, user group handle, tables guardrail
Every slack_* table and the app get help bundle text saying how rows get
created. Readiness and a new Check channels action persist the channel's
Slack name, privacy, bot membership, archived, purpose and checked time.
User group handle is resolved from usergroups.list and used in mentions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:04:29 -05:00
james.maes c5691102a2 Merge pull request #8 from QRun-IO/feature/interactivity
feat: phase 2 - interactive buttons as the clicking user, Events API revocations
2026-10-14 14:56:06 -05:00
james.maesandClaude Opus 5.5 0c298f893e feat(interactivity): button actions run as the clicking user; Events API revocations
POST /qqq/hooks/slack/interactions: verified, acknowledged, token checked
against the stored message, Slack user mapped to a connection in the same
workspace row, process run in that user's session with permission, tenant and
record locks; idempotent message update; ephemeral replies only to
hooks.slack.com. POST /qqq/hooks/slack/events: url_verification,
tokens_revoked and app_uninstalled across every tenant row of the team.
Built-in acknowledge_alert / resolve_alert when those processes exist.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 13:49:23 -05:00
james.maesandClaude Opus 5.5 fb93a01a41 feat(metadata): slack_interaction audit table (child of messages)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 13:49:22 -05:00
james.maesandClaude Opus 5.5 d486153ca8 feat(security): Slack request signature verifier and signed button tokens
v0 HMAC-SHA256 over timestamp and raw body, 300 s window, constant-time
compare; button values are server-signed (message, action, record, expiry).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 13:49:21 -05:00
james.maes 1d21f32835 Merge pull request #7 from QRun-IO/feature/delivery-destination
feat: phase 1e - Slack delivery destination, file uploads, SlackApi.applySessionKeys
2026-10-14 13:33:24 -05:00
james.maes f204e68331 Merge remote-tracking branch 'origin/develop' into feature/delivery-destination 2026-10-14 13:30:40 -05:00
james.maesandClaude Opus 5.5 8d5fa6d462 feat(delivery): Slack delivery destination and SlackApi.applySessionKeys
SlackDeliveryDestination: contingent pickers (workspace, then DM to me or a
channel the user is a member of), owner re-authorization, delivery template,
attachments as FILE messages, lookup mapping; built against
STAND-IN(core=QRun-IO/qqq#1205, removeBy=4.1.0-RC.8) copies of the core
delivery types. SlackApi.applySessionKeys so hosts stop using internal
SlackSecurity.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 13:30:38 -05:00
james.maesandClaude Opus 5.5 c0eab35fde feat(outbox): FILE messages via Slack's external upload flow
files.getUploadURLExternal, a streamed upload from core storage (no temp
files), files.completeUploadExternal; expired-lease reconcile by title marker
through files.list; files:read scope added to the manifest and design.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 13:30:37 -05:00
james.maes 3bbd282016 Merge pull request #6 from QRun-IO/feature/app-home
feat: phase 1f - Slack app, home dashboard, permissions, integrations, preferences
2026-10-14 13:13:57 -05:00
james.maesandClaude Opus 5.5 cbac87b0d8 fix(home): typed tables and statistic tiles instead of text blocks
Connections, recent deliveries, readiness and failures as linked tables;
non-zero status tiles linking to filtered Messages; local dates and readable
status labels; Fix hints only when not ready; one title.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 13:10:37 -05:00
james.maes 21553d67c1 Merge remote-tracking branch 'origin/develop' into feature/app-home 2026-10-14 12:49:18 -05:00
james.maesandClaude Opus 5.5 0bb2b463f0 feat(app): Slack app, viewer-scoped home dashboard and demo server
Nav lists only the six main tables; the home shows the user's connections and
deliveries and, for slack.admin, workspace readiness, outbox counts and recent
failures, all through owner and tenant locks. Test-scope demo server with the
fake Slack server and seeded data for screenshots.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:47:44 -05:00
james.maesandClaude Opus 5.5 6f81857cbe feat(preferences): Slack preferences section adapter and Connections record actions
Registers only when core user preferences exist:
STAND-IN(core=QRun-IO/qqq#1162, removeBy=4.1.0-RC.8). Connect, Disconnect,
Send me a test message and Install for my organization also work today as
record actions on Connections.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:47:43 -05:00
james.maesandClaude Opus 5.5 3f43130f14 feat(permissions): slack.* permissions, body masking, token-free API/ESB/Quick Search lists
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:47:43 -05:00
james.maes 2dab9e516c Merge pull request #5 from QRun-IO/feature/api-connect
feat: phase 1c/1d - Connect Slack (OAuth), SlackApi, readiness and health, templates, PHI guard
2026-10-14 12:37:42 -05:00
james.maes ce903dc5c1 Merge remote-tracking branch 'origin/develop' into feature/api-connect 2026-10-14 12:28:55 -05:00
james.maesandClaude Opus 5.5 f58c2318a3 feat(api): SlackApi public package, readiness and optional health check
isInstalled/send/sendOnce/reply/update/lookups/readiness/connectionsFor/
listTargets/ensureTemplate with token-free projections; readiness checks for
app, workspace, connection, registered channels and outbox, Check readiness
action, scheduled refresh; health registered only when qqq-middleware-health is
present.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:28:25 -05:00
james.maesandClaude Opus 5.5 c795e9fa01 feat(oauth): Connect Slack per user and Install per tenant
Signed, expiring OAuth state bound to user, tenant and session (stateless across
pods; per-pod replay set), callback route via the javalin extension (provided),
row-bound encrypted tokens, Disconnect (auth.revoke) and Uninstall actions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:28:24 -05:00
james.maesandClaude Opus 5.5 34035be6b2 feat(templates): Slack template engine and PHI payload guard
Email-compatible variable language with mrkdwn escaping, Block Kit variables in
string positions only, size and block limits, built-in notification, digest and
delivery templates; PHI/PII variables tokenized or refused, SSN/MRN patterns
refused, SECURITY sends title and link only, canary test.
STAND-IN(core=QRun-IO/qqq#1142, removeBy=4.1.0-RC.8) for classified value tokens.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 12:28:22 -05:00
james.maes 1e40970459 Merge pull request #2 from QRun-IO/feature/outbox-core
feat: phase 1b - tables, token cipher, owner/tenant authorization, outbox, dispatcher, core provider
2026-10-14 11:54:05 -05:00
james.maes 06eba71448 Merge remote-tracking branch 'origin/develop' into feature/outbox-core 2026-10-14 11:51:22 -05:00
james.maesandClaude Opus 5.5 2bb5fa7bc2 feat(bridge): QBIT_SLACK core messaging provider
Registered under bridgeProviderName (default slack) so callers use core
SendMessageAction only. STAND-IN(core=QRun-IO/qqq#1194, removeBy=4.1.0-RC.8)
for output status.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 11:51:03 -05:00
james.maesandClaude Opus 5.5 8d966e9bbe feat(outbox): durable outbox and dispatcher with exactly-once posting
Claim and lease with attempt rows; re-authorization as the owner at send time;
message-metadata reconcile of expired leases; 429 Retry-After without consuming
attempts; retries, dead letters, FAILED_AUTH with owner notification and alert;
threads, updates, rate limiter, workspace health. Two-tenant and token-leak tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 11:51:03 -05:00
james.maesandClaude Opus 5.5 efc7a7c82b feat(security): owner-session authorizer with membership check
Workspace and connection lookups run as the owner (createAutomatedSessionForUser)
so tenant and owner locks apply; conversations.members must include the owner;
bounded membership cache; only the chosen row's token is ever decrypted;
ownerless sends limited to registered channels with a matching tenant.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 11:51:02 -05:00
james.maesandClaude Opus 5.5 a45bb8a75e feat(transport): Slack Web API client, error classifier and fake test server
Bearer token per call (never stored), JSON writes, paged reads, Retry-After and
x-oauth-scopes, scrubbed errors, configurable timeouts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 11:51:01 -05:00
james.maesandClaude Opus 5.5 ac2427220e feat(metadata): slack_ tables with owner and tenant locks and hidden tokens
Seven tables (workspace, connection, channel, user group, template, message,
attempt), enums, joins, child lists and Postgres DDL. Owner locks on
connection and message; the host tenant lock on workspace and inherited by
join; token fields PASSWORD, hidden, and DENY-locked for every user session.
Tests: validator, owner isolation, two-tenant isolation, token invisibility.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 11:18:52 -05:00
james.maesandClaude Opus 5.5 82c13f2ff5 feat(security): AES-GCM token cipher bound to its row, and error scrubbing
Keys from named environment variables (current and previous), generic errors
with no cause, a canary test that a fake token never escapes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 11:18:51 -05:00
james.maesandClaude Opus 5.5 ab38448c51 feat(config): phase 1 settings, secret env-name allow list and validation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 11:18:50 -05:00
james.maes 317432b1d1 Merge pull request #1 from QRun-IO/feature/spec-and-scaffold
Design and scaffold: qbit-slack (per-user, multi-tenant Slack, delivery destinations)
2026-10-14 11:02:21 -05:00
james.maesandClaude Opus 5.5 cae5b88fa1 docs: design for qbit-slack (per-user, multi-tenant, delivery destinations)
Owner decisions (2026-10-14): all recommendations accepted (standing approval).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 10:59:39 -05:00
james.maesandClaude Opus 5.5 24be00bafc build: scaffold per the QRun qbit repository standard
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. Minimal SlackQBitProducer and SlackQBitConfig with a test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 10:59:38 -05:00
james.maes ee9e890117 Initial commit 2026-10-14 10:48:37 -05:00