SysEngineering

Slack Helpdesk Module

Slack helpdesk/offboarding module for common mailbox and Google Workspace tasks across many Workspace tenants. The clean Slack modal UI can be served by the Cloud Run backend, while the Apps Script file remains as the original prototype and fallback implementation.

For production, use backend/. It verifies Slack request signatures, routes by email domain, dispatches work through Cloud Tasks, impersonates the correct Google Workspace tenant, and DMs results back to the requester.

Files

See backend/README.md for Cloud Run deployment, route config, and tenant onboarding. For the 35+ Workspace rollout checklist, see backend/TENANT_ROLLOUT.md. For current project state and chat-to-chat continuation notes, see HANDOFF.md.

Supported Actions

Apps Script Properties

These apply only to offboard_tasks.js. The production Cloud Run backend uses environment variables documented in backend/README.md.

Route Config

Routes can be stored as an array:

[
  {
    "label": "Example Workspace",
    "domains": ["example.com", "example.org"],
    "adminEmail": "workspace-admin@example.com",
    "customerId": "my_customer",
    "gcpProjectId": "example-gcp-project"
  }
]

Or as a compact object keyed by domain:

{
  "example.com": {
    "label": "Example Workspace",
    "adminEmail": "workspace-admin@example.com"
  }
}

For route-specific service accounts, add "serviceAccountJsonProperty": "GW_SA_EXAMPLE_JSON" to a route and store that JSON in a separate Apps Script property.

Delegated Workspace Scopes

Authorize the service account client ID for domain-wide delegation in each Google Workspace tenant with these scopes:

Gmail settings calls impersonate the mailbox user being changed. Admin Directory calls, such as Google Group member lookups, impersonate the route’s adminEmail.

Production Guardrails

The production Cloud Run backend protects every route’s adminEmail automatically and checks Google Directory isAdmin in strict mode before every mailbox action. Add break-glass and other sensitive addresses to the route’s protectedEmails array. Protected addresses are rejected in Slack and again by the worker before Google API execution. See backend/README.md for the route format and preflight test.

For a direct Apps Script web app, set a long random SLACK_REQUEST_SECRET and append it to both Slack request URLs:

https://script.google.com/macros/s/.../exec?slack_secret=LONG_RANDOM_VALUE

Also set SLACK_ALLOWED_TEAM_IDS, SLACK_ALLOWED_API_APP_IDS, and SLACK_ALLOWED_USER_IDS before giving this to helpdesk. The allowlists are not a replacement for signed Slack requests, but they are useful blast-radius controls and catch accidental cross-workspace/app use.

For strongest production posture, put a small HTTPS service in front of Apps Script that verifies Slack’s X-Slack-Signature and X-Slack-Request-Timestamp headers, then forwards only verified requests to Apps Script. Keep the Apps Script URL secret and still use SLACK_REQUEST_SECRET between the proxy and Apps Script.

Slack requires slash commands to be acknowledged within 3 seconds. The slash command path does that now, but modal submissions run the Google action before returning. If group lookups or bundled actions start getting slow, move the execution step to a queue/worker and immediately DM the requester that the task has been accepted.

Validation

Run this from the repo root before redeploying the Apps Script source:

node --check integrations/slack_helpdesk_module/offboard_tasks.js

Run this before deploying the Cloud Run backend:

python -m py_compile integrations/slack_helpdesk_module/backend/main.py