A proxy service that enables Slack integration for GROWI instances, handling OAuth flows, event subscriptions, and message relay between Slack and GROWI.
| Component | Technology |
|---|---|
| Framework | Ts.ED 6.x (Express-based TypeScript framework) |
| Database | MySQL with TypeORM 0.2.x |
| Slack SDK | @slack/oauth, @slack/web-api |
| Views | EJS templates |
| Health Checks | @godaddy/terminus |
# Development
pnpm run dev # Start dev server with nodemon
# Quality Checks
pnpm run lint:typecheck # TypeScript type check
pnpm run lint:biome # Biome linter
pnpm run lint # Run all linters
# Build & Production
pnpm run build # Build for production
pnpm run start:prod # Start production server
src/
├── index.ts # Application entry point
├── Server.ts # Ts.ED server configuration
├── entities/ # TypeORM entities
│ ├── installation.ts # Slack app installation data
│ ├── relation.ts # GROWI-Slack relation mapping
│ ├── order.ts # Command order tracking
│ └── system-information.ts # System metadata
├── repositories/ # TypeORM repositories
├── controllers/ # Ts.ED controllers
│ ├── slack.ts # Slack event handlers
│ ├── growi-to-slack.ts # GROWI → Slack message relay
│ ├── top.ts # Landing page
│ ├── term.ts # Terms of service
│ └── privacy.ts # Privacy policy
├── services/ # Business logic
│ ├── InstallerService.ts # Slack app installation
│ ├── RegisterService.ts # GROWI registration
│ ├── RelationsService.ts # GROWI-Slack relations
│ └── growi-uri-injector/ # URI injection for Slack messages
├── middlewares/ # Express middlewares
│ ├── slack-to-growi/ # Slack → GROWI direction
│ └── growi-to-slack/ # GROWI → Slack direction
├── interfaces/ # TypeScript interfaces
├── filters/ # Error filters
├── config/ # Configuration files
│ ├── logger/ # Logging configuration
│ └── swagger/ # Swagger configuration
└── views/ # EJS templates
┌─────────┐ ┌────────────────┐ ┌───────┐
│ Slack │ ←→ │ Slackbot Proxy │ ←→ │ GROWI │
└─────────┘ └────────────────┘ └───────┘
| Entity | Description |
|---|---|
Installation |
Slack app installation data (tokens, team info) |
Relation |
Maps GROWI instances to Slack workspaces |
Order |
Tracks command execution order |
SystemInformation |
System metadata |
import { Controller, Post, Req, Res } from '@tsed/common';
import { SlackEventMiddleware } from '../middlewares/slack-to-growi/authorizer';
@Controller('/slack')
export class SlackController {
@Post('/events')
@UseBefore(SlackEventMiddleware)
async handleEvent(@Req() req: Request, @Res() res: Response) {
// Handle Slack event
}
}
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
@Entity()
export class Installation {
@PrimaryGeneratedColumn()
id: number;
@Column()
teamId: string;
@Column()
botToken: string;
}
Middlewares are organized by direction:
middlewares/slack-to-growi/ - Process incoming Slack eventsmiddlewares/growi-to-slack/ - Process outgoing messages to Slack
// middlewares/slack-to-growi/authorizer.ts
import { Middleware, Req, Next } from '@tsed/common';
@Middleware()
export class AuthorizerMiddleware {
use(@Req() req: Request, @Next() next: () => void) {
// Validate Slack signature
next();
}
}
| Method | Endpoint | Description |
|---|---|---|
| POST | /slack/events |
Slack event subscription endpoint |
| POST | /slack/interactions |
Slack interactive components |
| GET | /slack/oauth/callback |
OAuth callback |
| Method | Endpoint | Description |
|---|---|---|
| POST | /g2s/* |
GROWI to Slack relay |
| Method | Endpoint | Description |
|---|---|---|
| GET | / |
Landing page |
| GET | /term |
Terms of service |
| GET | /privacy |
Privacy policy |
| Variable | Description |
|---|---|
PORT |
Server port |
DATABASE_URL |
MySQL connection string |
SLACK_CLIENT_ID |
Slack app client ID |
SLACK_CLIENT_SECRET |
Slack app client secret |
SLACK_SIGNING_SECRET |
Slack signing secret |
TypeORM is configured with MySQL. Entity synchronization should be disabled in production.
// In Server.ts
@Configuration({
typeorm: {
connections: {
default: {
type: 'mysql',
url: process.env.DATABASE_URL,
entities: [Installation, Relation, Order, SystemInformation],
synchronize: process.env.NODE_ENV !== 'production',
},
},
},
})
pnpm run lint:typecheck # Type check
pnpm run lint:biome # Lint
pnpm run build # Verify build
GROWI instances register with the proxy using the @growi/slack package:
// In apps/app
import { SlackIntegration } from '@growi/slack';
const slack = new SlackIntegration({
proxyUrl: 'https://slackbot-proxy.example.com',
});
This service is deployed separately and requires its own MySQL database. It acts as a central hub for multiple GROWI instances to communicate with Slack.