Browse Source

add CLAUDE.md and AGENTS.md for other apps

Yuki Takei 2 months ago
parent
commit
f6544af30d

+ 162 - 0
apps/pdf-converter/AGENTS.md

@@ -0,0 +1,162 @@
+# GROWI PDF Converter (apps/pdf-converter)
+
+A microservice for converting GROWI pages to PDF format using Puppeteer.
+
+## Technology Stack
+
+| Component | Technology |
+|-----------|------------|
+| **Framework** | Ts.ED 8.x (Express-based TypeScript framework) |
+| **PDF Generation** | Puppeteer ^23.1.1 with puppeteer-cluster |
+| **API Documentation** | Swagger via @tsed/swagger |
+| **Health Checks** | @godaddy/terminus |
+
+## Quick Reference
+
+### Essential Commands
+
+```bash
+# Development
+pnpm run dev:pdf-converter          # Start dev server with nodemon
+
+# Quality Checks
+pnpm run lint:typecheck             # TypeScript type check
+pnpm run lint:biome                 # Biome linter
+pnpm run test                       # Run tests
+
+# 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
+├── controllers/
+│   ├── index.ts          # Controller exports
+│   ├── pdf.ts            # PDF conversion endpoint
+│   ├── pdf.spec.ts       # Controller tests
+│   └── terminus.ts       # Health check endpoint
+├── service/
+│   └── pdf-convert.ts    # Puppeteer PDF conversion logic
+└── bin/
+    └── index.ts          # CLI commands (swagger generation)
+```
+
+## Development Guidelines
+
+### 1. Ts.ED Controller Pattern
+
+Controllers use Ts.ED decorators:
+
+```typescript
+import { Controller, Get, Post } from '@tsed/common';
+import { Returns } from '@tsed/schema';
+
+@Controller('/pdf')
+export class PdfController {
+  @Post('/')
+  @Returns(200, Buffer)
+  async convert(@BodyParams() body: ConvertRequest): Promise<Buffer> {
+    return this.pdfService.convert(body.html);
+  }
+}
+```
+
+### 2. Puppeteer Service
+
+The PDF conversion service uses puppeteer-cluster for parallel processing:
+
+```typescript
+// service/pdf-convert.ts
+import { Cluster } from 'puppeteer-cluster';
+
+export class PdfConvertService {
+  private cluster: Cluster;
+
+  async convert(html: string): Promise<Buffer> {
+    return this.cluster.execute(html, async ({ page, data }) => {
+      await page.setContent(data);
+      return page.pdf({ format: 'A4' });
+    });
+  }
+}
+```
+
+### 3. Health Checks
+
+Use @godaddy/terminus for Kubernetes-compatible health endpoints:
+
+- `/health/liveness` - Is the service alive?
+- `/health/readiness` - Is the service ready to accept requests?
+
+## API Endpoints
+
+| Method | Endpoint | Description |
+|--------|----------|-------------|
+| POST | `/pdf` | Convert HTML to PDF |
+| GET | `/health/liveness` | Liveness probe |
+| GET | `/health/readiness` | Readiness probe |
+
+### Generate Swagger Spec
+
+```bash
+pnpm run gen:swagger-spec
+```
+
+Outputs to `specs/` directory.
+
+## Environment Variables
+
+| Variable | Description | Default |
+|----------|-------------|---------|
+| `PORT` | Server port | 3001 |
+| `SKIP_PUPPETEER_INIT` | Skip Puppeteer initialization (for tests) | false |
+
+## Testing
+
+Tests use Vitest with supertest for HTTP assertions:
+
+```typescript
+import { describe, it, expect } from 'vitest';
+import supertest from 'supertest';
+
+describe('PdfController', () => {
+  it('should convert HTML to PDF', async () => {
+    const response = await supertest(app)
+      .post('/pdf')
+      .send({ html: '<h1>Hello</h1>' });
+
+    expect(response.status).toBe(200);
+    expect(response.headers['content-type']).toContain('application/pdf');
+  });
+});
+```
+
+## Integration with GROWI
+
+The main GROWI app (`apps/app`) uses `@growi/pdf-converter-client` package to communicate with this service:
+
+```typescript
+// In apps/app
+import { PdfConverterClient } from '@growi/pdf-converter-client';
+
+const client = new PdfConverterClient('http://pdf-converter:3001');
+const pdfBuffer = await client.convert(pageHtml);
+```
+
+## Before Committing
+
+```bash
+pnpm run lint:typecheck   # Type check
+pnpm run lint:biome       # Lint
+pnpm run test             # Run tests
+pnpm run build            # Verify build
+```
+
+---
+
+This service is deployed separately from the main GROWI application and communicates via HTTP.

+ 1 - 0
apps/pdf-converter/CLAUDE.md

@@ -0,0 +1 @@
+@AGENTS.md

+ 222 - 0
apps/slackbot-proxy/AGENTS.md

@@ -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.

+ 1 - 0
apps/slackbot-proxy/CLAUDE.md

@@ -0,0 +1 @@
+@AGENTS.md