Boosting Productivity and Streamlining Support with a Slack Bot: Our Team Solution

Gülümser Aslan
Trendyol Tech
Published in
6 min readJun 15, 2023

The Product Reward and Compliance team is a dedicated team responsible for managing product-related domains for our sellers in Trendyol. Our team focuses on ensuring the originality of products, controlling trademark processes, applying automated price rules, and managing fast delivery tags. While our primary role revolves around these critical points, we occasionally find ourselves providing support due to our collaborations with different teams and third-party firms.

In this article, we will explore how we created a Slack bot to simplify our support procedures and reduce the workload on our team. By automating specific tasks and offering immediate help to our sellers, we successfully saved time and redirected our resources to focus on our main responsibilities: maintaining product integrity and providing a positive seller experience.

Introduction

In today’s fast-paced work environments, many companies use platforms like Slack for team collaboration and communication. Slack has gained popularity because it’s easy to use, allows real-time messaging, offers integration options, and enables the creation of custom apps and bots.

In Trendyol, we also use Slack. Each team has its own dedicated support channels where team members can post their support-related issues. Sometimes, our team receives hundreds of support messages, and it can be inefficient for the team to manually review and handle all of them. Support requests can often overwhelm a team, leading to delays in responses and repetitive inquiries. Understanding this challenge within our team, we develop a solution that would simplify the support process and offer instant help to our team members.

Our Solution

Our Slack bot functions as an automated system that allows us to respond quickly and efficiently to users. It understands specific commands, providing customized responses for each request and accurately interpreting user instructions.

Implementation Details

We used the Slack API for creating bots to develop our solution. We utilized Java and Spring Boot to build the bot’s features. The bot is containerized using Docker and operates on a server, guaranteeing it stays online and accessible to assist team members whenever they need it.

1. Bot Implementation

First of all, we create a Slack App and configure its settings. We create our app from this page by clicking on “Create an App.” After creation, we configure the app. We should add the necessary permission scopes based on the functionality we want our app to have. Our app’s scopes and its configuration are displayed below:

After the configuration part, we installed App to our workspace we received an “OAuth Access Token” — this token will be used to authenticate your app’s requests to the Slack API. We can add our app to the Slack channel which we want and we are ready to use our Slack app.

2. Code Implementation

We should create an app that connects to Slack and handle Slack events. Since our team is more familiar with Java, we developed a Java application. With Java, we can handle incoming messages, process commands, and generate dynamic responses.

We connect to Slack API with Socket Mode. Socket Mode gives your app a way to connect to Slack, without exposing a public HTTP endpoint. Socket Mode allows your app to communicate with Slack via a WebSocket URL. WebSockets use a bidirectional stateful protocol with low latency to communicate between two parties — in this case, Slack and our app.

We use slack.api.bolt and socket_mode dependencies. An App instance is created using the bot token. The app registers an event listener for AppMentionEvent and delegates handling to the appMentionEventHandler bean. A SocketModeApp is configured with App instance and app token. The SocketModeApp is started, establishing a connection to the Slack API:

package trendyol.slack.support;

import com.slack.api.bolt.App;
import com.slack.api.bolt.AppConfig;
import com.slack.api.bolt.socket_mode.SocketModeApp;
import com.slack.api.model.event.AppMentionEvent;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SlackAppSocketModeConfig {

private final AppMentionEventHandler appMentionEventHandler;

public SlackAppSocketModeConfig(AppMentionEventHandler appMentionEventHandler) {
this.appMentionEventHandler = appMentionEventHandler;
}

@Bean
public void slackApp() {
String botToken = // your "SLACK_BOT_TOKEN"
App app = new App(AppConfig.builder().singleTeamBotToken(botToken).build());
app.event(AppMentionEvent.class, appMentionEventHandler::handle);
String appToken = // your "SLACK_APP_TOKEN"
SocketModeApp socketModeApp = new SocketModeApp(appToken, app);
socketModeApp.start();
}

}

Now, we are ready to deep into appMentionEventHandler. AppMentionEvent which is sent whenever your app is mentioned via @ in a Slack channel. After the bot is mentioned, we parse the command, find to proper response service, and then prepare a brief message to the same channel the mention was posted in:

package trendyol.slack.support;

import com.slack.api.app_backend.events.payload.EventsApiPayload;
import com.slack.api.bolt.context.builtin.EventContext;
import com.slack.api.bolt.response.Response;
import com.slack.api.methods.SlackApiException;
import com.slack.api.model.event.AppMentionEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class AppMentionEventHandler {

private static final Logger LOGGER = LoggerFactory.getLogger(AppMentionEventHandler.class);

private final SupportFactory supportFactory;
private final SlackService slackService;

public AppMentionEventHandler(SupportFactory supportFactory,
SlackService slackService) {
this.supportFactory = supportFactory;
this.slackService = slackService;
}

public void handle(EventsApiPayload<AppMentionEvent> eventsApiPayload, EventContext context) {
try {
SupportService<EventsApiPayload<AppMentionEvent>> supportService = supportFactory.findSupportService(eventsApiPayload);
String slackResponse = supportService.handle(eventsApiPayload);
slackService.tryToSendMessage(eventsApiPayload.getEvent(), slackResponse);
} catch (Exception ex) {
LOGGER.error("An error is occurred while sending message to slack.", ex);
context.say("Hello, there is a problem. Please try again later");
context.ack();
}
}

}

The following code represents an interface called SupportService with a generic object type.

The SupportService interface has four methods:

  • handle(T event): It is responsible for handling the event and generating a suitable response.
  • isExecutable(T event): It is used to determine if the event can be processed by the service.
  • getCommand(): It provides information about the specific command that triggers this service.
  • getHelpText(): It provides guidance or information on how to use the command associated with the service.
package trendyol.slack.support;

public interface SupportService<T> {

String handle(T event);

Boolean isExecutable(T event);

String getCommand();

String getHelpText();
}

The following code is designed to handle Slack events and provide appropriate responses based on user commands.

The ExampleProductSupportService class implements the SupportService interface, which defines methods for handling events, checking if an event is executable, and retrieving the associated command and help text.

The service extracts information from Slack events, such as the mentioned command and user message. It uses helper methods to parse and modify the command. Then, it generates a response by combining a hello message with the product’s response.

By implementing this service, it becomes possible to handle Slack events related to product support efficiently, providing relevant responses to users and ensuring a smooth support experience.

package trendyol.slack.support;

import com.slack.api.app_backend.events.payload.EventsApiPayload;
import com.slack.api.model.event.AppMentionEvent;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.Objects;

@Service
public class ExampleProductSupportService implements SupportService<EventsApiPayload<AppMentionEvent>> {

private final ExampleResponseConverter exampleResponseConverter;

public ExampleProductSupportService(ExampleResponseConverter exampleResponseConverter) {
this.exampleResponseConverter = exampleResponseConverter;
}

@Override
public Boolean isExecutable(EventsApiPayload<AppMentionEvent> payload) {
return payload.getEvent().getText().contains(getCommand());
}

@Override
public String getCommand() {
return "example command:";
}

@Override
public String getHelpText() {
return "example help text";
}

@Override
public String handle(EventsApiPayload<AppMentionEvent> payload) {
AppMentionEvent event = payload.getEvent();
String parsedCommand = parseCommand(event);
String helloMessage = getHelloMessage(event);
return StringUtils.isNotBlank(parsedCommand) ? getResponse(parsedCommand, helloMessage) : getHelpText();
}

private String parseCommand(AppMentionEvent event) {
String userCommand = replaceBotUserAndCommand(event.getText());
return StringUtils.isNotBlank(userCommand) ? userCommand : getHelpText();
}

private String replaceBotUserAndCommand(String text) {
String botUserId = // your "BOT_SLACK_USER_ID";
text = text.replace(botUserId, "");
text = text.replace(getCommand(), "");
return text;
}

private String getResponse(String userCommand, String helloMessage) {
String productResponse = exampleResponseConverter.generateResponse(userCommand);
return helloMessage + productResponse;
}

private String getHelloMessage(AppMentionEvent event) {
String helloMessage = "Hello";
String userMentionMessage= " <@%s>,";
return Objects.nonNull(event.getUser()) ? helloMessage + String.format(userMentionMessage, event.getUser()): helloMessage;
}

}

Here’s an example of our bot reply:

Conclusion

By developing a Slack bot that dynamically responds to user commands, we successfully reduced the internal support workload and improved team productivity. The bot’s ability to provide instant assistance and relevant information has empowered our team members, enabling them to find answers quickly and efficiently. Leveraging the automation process, organizations can optimize their support processes and create a seamless and productive work environment.

And finally, I would like to thank my dear teammates Özge Onay and Sevgi Erbas for their contribution to the bot development processes.

Thank you for reading.

Resources: https://api.slack.com/apis/connections/socket

Be a part of something great! Trendyol is currently hiring. Visit the pages below for more information and to apply.

--

--