|
|
@@ -0,0 +1,222 @@
|
|
|
+# GROWI Slackbot Proxy (apps/slackbot-proxy)
|
|
|
+
|
|
|
+A proxy service that enables Slack integration for GROWI instances, handling OAuth flows, event subscriptions, and message relay between Slack and GROWI.
|
|
|
+
|
|
|
+## Technology Stack
|
|
|
+
|
|
|
+| 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 |
|
|
|
+
|
|
|
+## Quick Reference
|
|
|
+
|
|
|
+### Essential Commands
|
|
|
+
|
|
|
+```bash
|
|
|
+# 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
|
|
|
+```
|
|
|
+
|
|
|
+### Directory Structure
|
|
|
+
|
|
|
+```
|
|
|
+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
|
|
|
+```
|
|
|
+
|
|
|
+## Architecture
|
|
|
+
|
|
|
+### Message Flow
|
|
|
+
|
|
|
+```
|
|
|
+┌─────────┐ ┌────────────────┐ ┌───────┐
|
|
|
+│ Slack │ ←→ │ Slackbot Proxy │ ←→ │ GROWI │
|
|
|
+└─────────┘ └────────────────┘ └───────┘
|
|
|
+```
|
|
|
+
|
|
|
+1. **Slack → GROWI**: Slack events/commands are received, validated, and forwarded to registered GROWI instances
|
|
|
+2. **GROWI → Slack**: GROWI sends notifications/responses through the proxy to Slack
|
|
|
+
|
|
|
+### Key Entities
|
|
|
+
|
|
|
+| 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 |
|
|
|
+
|
|
|
+## Development Guidelines
|
|
|
+
|
|
|
+### 1. Ts.ED Controller Pattern
|
|
|
+
|
|
|
+```typescript
|
|
|
+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
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 2. TypeORM Entity Pattern
|
|
|
+
|
|
|
+```typescript
|
|
|
+import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
|
|
+
|
|
|
+@Entity()
|
|
|
+export class Installation {
|
|
|
+ @PrimaryGeneratedColumn()
|
|
|
+ id: number;
|
|
|
+
|
|
|
+ @Column()
|
|
|
+ teamId: string;
|
|
|
+
|
|
|
+ @Column()
|
|
|
+ botToken: string;
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 3. Middleware Pattern (Bidirectional)
|
|
|
+
|
|
|
+Middlewares are organized by direction:
|
|
|
+
|
|
|
+- `middlewares/slack-to-growi/` - Process incoming Slack events
|
|
|
+- `middlewares/growi-to-slack/` - Process outgoing messages to Slack
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 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();
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+## API Endpoints
|
|
|
+
|
|
|
+### Slack Events
|
|
|
+
|
|
|
+| Method | Endpoint | Description |
|
|
|
+|--------|----------|-------------|
|
|
|
+| POST | `/slack/events` | Slack event subscription endpoint |
|
|
|
+| POST | `/slack/interactions` | Slack interactive components |
|
|
|
+| GET | `/slack/oauth/callback` | OAuth callback |
|
|
|
+
|
|
|
+### GROWI Integration
|
|
|
+
|
|
|
+| Method | Endpoint | Description |
|
|
|
+|--------|----------|-------------|
|
|
|
+| POST | `/g2s/*` | GROWI to Slack relay |
|
|
|
+
|
|
|
+### Web Pages
|
|
|
+
|
|
|
+| Method | Endpoint | Description |
|
|
|
+|--------|----------|-------------|
|
|
|
+| GET | `/` | Landing page |
|
|
|
+| GET | `/term` | Terms of service |
|
|
|
+| GET | `/privacy` | Privacy policy |
|
|
|
+
|
|
|
+## Environment Variables
|
|
|
+
|
|
|
+| 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 |
|
|
|
+
|
|
|
+## Database Configuration
|
|
|
+
|
|
|
+TypeORM is configured with MySQL. Entity synchronization should be disabled in production.
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 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',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+})
|
|
|
+```
|
|
|
+
|
|
|
+## Before Committing
|
|
|
+
|
|
|
+```bash
|
|
|
+pnpm run lint:typecheck # Type check
|
|
|
+pnpm run lint:biome # Lint
|
|
|
+pnpm run build # Verify build
|
|
|
+```
|
|
|
+
|
|
|
+## Integration with GROWI
|
|
|
+
|
|
|
+GROWI instances register with the proxy using the `@growi/slack` package:
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 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.
|