Skip to content

heroku-examples/slack-approval-app

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

24 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Universal Approval Hub

A Proof of Concept (POC) application that demonstrates how Slack, integrated with Heroku, can act as a Universal Approval Hub, centralizing approval requests from various Systems of Record (e.g., Workday, Concur, Salesforce).

Note: This is a demonstration application. The Workday, Concur, and Salesforce integrations are mocked - the app accepts requests via a REST API endpoint that simulates webhooks from these systems, but does not actually connect to external services. The application can be extended to integrate with real systems by implementing webhook handlers or API clients for each service.

Features

  • Slack Home Tab Dashboard: Personalized approval dashboard for managers
  • Multi-Source Support: Handles approval requests from Workday, Concur, and Salesforce (mocked for demo purposes)
  • Semantic Search: Natural language search using Heroku Managed Inference and pgvector
  • AI-Powered Analysis: Automatic summarization and risk scoring using Claude
  • Real-Time Updates: Instant UI updates when approvals are processed
  • Secure Webhooks: Slack request verification and secure API endpoints
  • Web Interface: User-friendly forms and status dashboard for creating and viewing test requests

Architecture

  • Backend: Flask (Python 3.11)
  • Database: Heroku Postgres (or Heroku Postgres Advanced) with pgvector extension
  • AI/ML: Heroku Managed Inference (Cohere embeddings, Claude chat completions)
  • Deployment: Heroku with Gunicorn
  • Integration: Slack Events API, Interactive Components, Home Tab

Note: This application is designed for Heroku deployment and uses Heroku Postgres. For production workloads requiring high performance and scale, consider Heroku Postgres Advanced, the next generation of Heroku Postgres with enhanced performance, scalability, and zero-friction operations.

Prerequisites

  • Python 3.11+
  • Heroku account (for deployment)
  • Heroku Postgres add-on (automatically configured via DATABASE_URL)
  • Slack App with appropriate OAuth scopes
  • Heroku Managed Inference add-on (optional, for AI features)

For Local Development Only: PostgreSQL 12+ with pgvector extension (see Local Development Setup below)

Deployment to Heroku

πŸ“‹ Workshop Focus: This section covers Heroku deployment, which is the primary focus of the workshop. For local development setup (outside workshop scope), see Local Development Setup below.

This application is designed to run on Heroku with Heroku Postgres. The DATABASE_URL environment variable is automatically set when you attach a Postgres add-on to your Heroku app.

1. Create Heroku App

heroku create your-app-name

2. Add Heroku Postgres Add-on

For standard workloads:

heroku addons:create heroku-postgresql:essential-0 --app your-app-name

For high-performance, scalable workloads, consider Heroku Postgres Advanced (pilot program):

  • Sign up for the Heroku Postgres Advanced pilot
  • Provides 4X+ throughput, 200TB+ storage, and zero-downtime scaling
  • Once available, provision via Heroku dashboard or CLI

Note: Heroku Postgres Advanced will eventually replace Standard, Premium, Private, and Shield tiers. The application automatically detects and uses the DATABASE_URL provided by any Heroku Postgres add-on.

3. Add Heroku Managed Inference (Optional)

heroku addons:create heroku-managed-inference:starter --app your-app-name

4. Set Environment Variables

heroku config:set SECRET_KEY=your-secret-key --app your-app-name
heroku config:set SLACK_BOT_TOKEN=xoxb-your-token --app your-app-name
heroku config:set SLACK_SIGNING_SECRET=your-signing-secret --app your-app-name
heroku config:set SLACK_APP_ID=your-app-id --app your-app-name

Note: DATABASE_URL is automatically set by Heroku when you attach a Postgres add-on. You do not need to set it manually.

5. Deploy

git push heroku main

6. Initialize Database

The application will automatically:

  • Enable the pgvector extension
  • Create all required tables
  • Set up the database schema

You can also manually run the setup script:

heroku run python scripts/setup_db.py --app your-app-name

7. Seed Data (Optional)

heroku run python scripts/seed_data.py --app your-app-name

8. Verify Deployment

Check that your app is running:

heroku open --app your-app-name

View logs:

heroku logs --tail --app your-app-name

Local Development Setup

Note: Local development setup is outside the scope of the workshop. This section is provided for developers who want to run the application locally for development or testing purposes.

1. Clone the Repository

git clone <repository-url>
cd UniversalApprovalHub

2. Create Virtual Environment

python3 -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

3. Install Dependencies

pip install -r requirements.txt

4. Set Up PostgreSQL with pgvector

Using Homebrew (macOS):

brew install postgresql@14
brew install pgvector

Using Docker:

docker run -d \
  --name approval-hub-db \
  -e POSTGRES_PASSWORD=postgres \
  -e POSTGRES_DB=approval_hub \
  -p 5432:5432 \
  pgvector/pgvector:pg14

5. Configure Environment Variables

Create a .env file in the project root:

# Flask Configuration
FLASK_APP=app.py
FLASK_ENV=development
SECRET_KEY=your-secret-key-here

# Database Configuration
DATABASE_URL=postgresql://user:password@localhost:5432/approval_hub

# Slack Configuration
SLACK_BOT_TOKEN=xoxb-your-bot-token
SLACK_SIGNING_SECRET=your-signing-secret
SLACK_APP_ID=your-app-id

# Heroku Managed Inference (when add-on is provisioned)
HEROKU_MANAGED_INFERENCE_API_URL=https://api.heroku.com/managed-inference/v1
HEROKU_MANAGED_INFERENCE_API_KEY=your-api-key

# Logging
LOG_LEVEL=INFO

6. Initialize Database

python scripts/setup_db.py

7. Seed Sample Data

python scripts/seed_data.py

8. Run the Application

python app.py

The application will be available at http://localhost:5000

Slack App Configuration

⚠️ IMPORTANT: If you don't see the Home Tab interface when opening the app in Slack, you likely need to enable the Home Tab feature in your Slack app settings. See SLACK_SETUP.md for detailed step-by-step configuration instructions.

Required Bot Token OAuth Scopes

The following Bot Token scopes are required:

  • chat:write - Required - Send messages as the bot and manage Home Tab content
  • users:read - Required - View people in the workspace
  • users:read.email - Required - View email addresses of people in the workspace
  • app_mentions:read - Read mentions of your app (optional, if using mentions)
  • channels:history - View messages in public channels (optional, if needed)
  • commands - Add slash commands (optional, if using slash commands)

Note: The app_home:write scope is not available in Slack's current permission model. The chat:write scope is sufficient for publishing Home Tab views via views.publish(). Additionally, the Home Tab endpoint (/slack/home) approach used by this app doesn't require any special scope beyond chat:write.

How to Configure Bot Token Scopes in Slack

  1. Navigate to your Slack App:

  2. Open OAuth & Permissions:

    • In the left sidebar, click "OAuth & Permissions" (under Features)
  3. Add Bot Token Scopes:

    • Scroll down to the "Scopes" section
    • Find the "Bot Token Scopes" subsection
    • Click "Add New Scope" button
    • Add each of the required scopes listed above:
      • chat:write (required)
      • users:read (required)
      • users:read.email (required)
      • app_mentions:read (optional)
      • channels:history (optional)
      • commands (optional)
  4. Install/Reinstall the App:

    • After adding scopes, scroll to the top of the page
    • Click "Install to Workspace" (or "Reinstall to Workspace" if already installed)
    • Review the permissions and click "Allow"
  5. Copy the Bot Token:

    • After installation, you'll see "Bot User OAuth Token" at the top of the page
    • Copy this token (starts with xoxb-)
    • Set it as SLACK_BOT_TOKEN in your environment variables

Note: If you add new scopes after the app is already installed, you must reinstall the app to your workspace for the new scopes to take effect.

App-Level Token Scopes (Optional)

App-level tokens are NOT required for the current webhook-based implementation. This application uses:

  • Events API (webhooks) for receiving events
  • Interactive Components (webhooks) for button interactions
  • Bot tokens for publishing Home Tab views and sending messages

If you plan to use Socket Mode instead of webhooks (for development or firewall-restricted environments), you would need an app-level token with:

  • connections:write - Connect to Slack via Socket Mode

To create an app-level token:

  1. Go to your Slack app settings β†’ Basic Information
  2. Scroll to App-Level Tokens
  3. Click Generate Token and Scopes
  4. Add the connections:write scope
  5. Copy the token (starts with xapp-)

Note: For production deployments on Heroku, webhooks are recommended as they're more reliable and don't require maintaining persistent WebSocket connections.

Event Subscriptions

Configure the following events:

  • app_home_opened - Triggered when a user opens the Home Tab

Set the Request URL to:

https://your-app.herokuapp.com/slack/events

Interactive Components

Enable Interactive Components and set the Request URL to:

https://your-app.herokuapp.com/slack/interactive

Slash Commands (Optional)

No slash commands are required for this POC.

API Endpoints

βœ… Swagger/OpenAPI Documentation Available: Interactive API documentation is available at /api-docs when the application is running. The documentation is automatically generated from Flask docstrings using Flasgger.

Access Swagger UI:

  • Local: http://localhost:5000/api-docs
  • Heroku: https://your-app.herokuapp.com/api-docs

The codebase includes:

  • Comprehensive docstrings: Sphinx-style with :param:, :return:, :rtype: tags
  • Type hints: Function signatures include type hints using typing module
  • Swagger/OpenAPI: Interactive documentation via Flasgger at /api-docs

Health Check

GET /health

Returns application health status.

Response:

{
  "status": "healthy",
  "service": "universal-approval-hub"
}

Create Approval Request

POST /api/new-approval
Content-Type: application/json

Creates a new approval request from external system webhook (or web form).

Request Body:

{
  "request_source": "Workday|Concur|Salesforce",
  "requester_name": "John Doe",
  "approver_id": "U123456",
  "justification_text": "Request justification...",
  "metadata": {
    "date_range": "2024-01-01 to 2024-01-05",
    "amount": 500.00,
    ...
  }
}

Response (201 Created):

{
  "id": 1,
  "status": "created",
  "message": "Approval request created successfully"
}

Get Approval Requests

GET /api/requests?status=Pending&source=Workday&approver_id=U123456

Fetches approval requests with optional filtering.

Query Parameters:

  • status (optional): Filter by status (Pending, Approved, Rejected)
  • source (optional): Filter by source (Workday, Concur, Salesforce)
  • approver_id (optional): Filter by approver Slack User ID

Response (200 OK):

{
  "requests": [...],
  "count": 5
}

Slack Events

POST /slack/events

Handles Slack Events API callbacks (URL verification, app_home_opened events).

Slack Interactive Components

POST /slack/interactive

Handles button clicks (approve/reject) and other interactive components.

Slack Home Tab

POST /slack/home

Returns Home Tab view for a user (deprecated - use Events API instead).

Database Schema

approval_requests

Field Type Description
id SERIAL Primary key
request_source VARCHAR(50) Source system (Workday, Concur, Salesforce)
requester_name VARCHAR(100) Employee name
approver_id VARCHAR(50) Slack User ID of approver
status VARCHAR(20) Pending, Approved, Rejected
justification_text TEXT Request justification
metadata_json JSONB Source-specific metadata
search_vector VECTOR(1024) Embedding vector for semantic search
created_at TIMESTAMP Creation timestamp
updated_at TIMESTAMP Last update timestamp

Testing

Unit Tests

Run the test suite:

pytest

Run with coverage:

pytest --cov=. --cov-report=html

Creating Test Approval Requests

To test the approval flow without connecting to external systems, you can create mock approval requests. See TESTING.md for detailed instructions.

🌟 Recommended: Web Interface (Perfect for Workshops/Demos)

The easiest way is through the web interface - no command line needed!

  1. Open your browser and navigate to:

    https://your-app.herokuapp.com/create-request
    
  2. Fill out the form and click "Create Request" - the request will appear in your Slack Home Tab!

  3. You'll be redirected to the Status Dashboard (/status) to view all requests and their statuses

Alternative Methods:

# On Heroku (script)
heroku run python scripts/create_test_request.py --samples --approver-id YOUR_SLACK_USER_ID --app your-app-name

# Or use the API
curl -X POST https://your-app.herokuapp.com/api/new-approval \
  -H "Content-Type: application/json" \
  -d '{
    "request_source": "Workday",
    "requester_name": "John Doe",
    "approver_id": "YOUR_SLACK_USER_ID",
    "justification_text": "Test PTO request",
    "metadata": {"date_range": "2024-02-15 to 2024-02-22"}
  }'

Project Structure

UniversalApprovalHub/
β”œβ”€β”€ app.py                 # Main Flask application
β”œβ”€β”€ config.py             # Configuration classes
β”œβ”€β”€ database.py            # Database initialization
β”œβ”€β”€ models.py              # SQLAlchemy models
β”œβ”€β”€ requirements.txt       # Python dependencies
β”œβ”€β”€ Procfile              # Heroku process definition
β”œβ”€β”€ .python-version       # Python version specification
β”œβ”€β”€ routes/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ api_routes.py     # External API endpoints
β”‚   └── slack_routes.py   # Slack integration routes
β”œβ”€β”€ utils/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ logging_config.py # Logging setup
β”‚   β”œβ”€β”€ heroku_inference.py # AI/ML integration
β”‚   β”œβ”€β”€ semantic_search.py # Vector search utilities
β”‚   └── slack_utils.py    # Slack helper functions
β”œβ”€β”€ migrations/
β”‚   └── 001_initial_schema.sql # Database schema
β”œβ”€β”€ scripts/
β”‚   β”œβ”€β”€ setup_db.py       # Database setup script
β”‚   └── seed_data.py      # Sample data seeding
└── tests/
    β”œβ”€β”€ conftest.py       # Pytest fixtures
    β”œβ”€β”€ test_api_routes.py
    β”œβ”€β”€ test_slack_routes.py
    └── test_models.py

Environment Variables Reference

Variable Description Required Set By
SECRET_KEY Flask secret key Yes Manual
DATABASE_URL PostgreSQL connection string Yes Heroku (auto)
SLACK_BOT_TOKEN Slack Bot User OAuth Token Yes Manual
SLACK_SIGNING_SECRET Slack Signing Secret Yes Manual
SLACK_APP_ID Slack App ID Yes Manual
HEROKU_MANAGED_INFERENCE_API_URL Managed Inference API URL No Heroku (auto)
HEROKU_MANAGED_INFERENCE_API_KEY Managed Inference API Key No Heroku (auto)
LOG_LEVEL Logging level (DEBUG, INFO, WARNING, ERROR) No Manual

Important: DATABASE_URL is automatically configured by Heroku when you attach a Postgres add-on. The application handles both postgres:// and postgresql:// connection strings and configures SSL automatically for Heroku Postgres.

Troubleshooting

Database Connection Issues

On Heroku:

  • Verify Postgres add-on is attached: heroku addons
  • Check DATABASE_URL is set: heroku config:get DATABASE_URL
  • The application automatically enables pgvector extension on first run
  • View database logs: heroku logs --ps postgres

Local Development:

  • Ensure PostgreSQL is running locally
  • Verify DATABASE_URL in .env file is correct
  • Check that pgvector extension is installed: CREATE EXTENSION vector;

Slack Integration Issues

  • Verify all OAuth scopes are granted
  • Check that Event Subscriptions URL is correct
  • Ensure signing secret matches Slack app configuration

Heroku Managed Inference

  • Verify add-on is provisioned: heroku addons
  • Check environment variables are set: heroku config
  • Review logs: heroku logs --tail

Contributing

  1. Follow PEP 8 style guidelines
  2. Include docstrings for all functions and classes (Sphinx-style with :param:, :return:, :rtype:)
  3. Add type hints to function signatures (using typing module)
  4. Write tests for new features
  5. Run tests before submitting: pytest (or pytest --cov=. for coverage)
  6. Update documentation as needed

Code Documentation Standards

The project uses:

  • Docstrings: Sphinx-style docstrings with :param:, :return:, :rtype: tags
  • Type Hints: Function signatures include type hints using typing module
  • API Documentation: Currently manual (see API Endpoints section above). Swagger/OpenAPI not yet implemented.

Running Tests

# Install test dependencies (if not already installed)
pip install -r requirements.txt

# Run all tests
pytest

# Run with coverage report
pytest --cov=. --cov-report=html

# Run specific test file
pytest tests/test_api_routes.py

License

This project is licensed under the Apache License 2.0. See the LICENSE file for details.

Support

For issues and questions, please create an issue or contact the development team.

About

Slack based approval app hosted on Heroku

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors