From 046d9459ac6fc46600fab4db488789798b7582ff Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 15 May 2026 00:54:37 +0000 Subject: [PATCH 1/2] fix: resolve Prisma schema relations, DI issues, and add dev environment setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add missing reverse relation fields in Prisma schema (bots→Workspace, botMessages→Channel/ChatMessage) - Fix BotHandlerType enum type mismatch in bots.service.ts - Add definite assignment assertions to DTO properties for strict mode compatibility - Import AuthModule in BotsModule and SearchModule for JwtAuthGuard DI - Add backend/config/projectTemplates.json required by TemplateService at startup - Add AGENTS.md with cloud development instructions - Add package-lock.json files for deterministic installs Co-authored-by: RedWoodOG --- AGENTS.md | 57 +++++++++++ backend/config/projectTemplates.json | 39 ++++++++ backend/package-lock.json | 96 ++++++++++++++++++ backend/prisma/schema.prisma | 3 + backend/src/bots/bots.module.ts | 2 + backend/src/bots/bots.service.ts | 9 +- backend/src/bots/dto/bot.dto.ts | 10 +- backend/src/search/search.module.ts | 3 +- bot-sdk/package-lock.json | 141 +++++++++++++++++++++++++++ 9 files changed, 351 insertions(+), 9 deletions(-) create mode 100644 AGENTS.md create mode 100644 backend/config/projectTemplates.json create mode 100644 bot-sdk/package-lock.json diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..30be3597 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,57 @@ +# AGENTS.md + +## Cursor Cloud specific instructions + +### Services Overview + +| Service | How to run | Port | +|---------|-----------|------| +| Backend (NestJS) | `cd backend && npm run start:dev` | 4000 | +| Bot SDK | `cd bot-sdk && npm run build` | N/A (library) | + +### Backend Dev Server + +- **Start**: `cd backend && npm run start:dev` (uses nodemon + ts-node) +- **Health check**: `GET http://localhost:4000/api/v1/health` +- **API prefix**: `/api/v1` +- **WebSocket**: `ws://localhost:4000` (Socket.IO) + +### Prerequisites (must be running before backend starts) + +- **PostgreSQL** on `localhost:5432` — database `flowspace`, user `flowspace`/`flowspace` +- **Redis** on `localhost:6379` — used for Socket.IO horizontal scaling; backend gracefully falls back to in-memory adapter if unavailable + +Start services: +```bash +sudo pg_ctlcluster 16 main start +sudo redis-server --daemonize yes +``` + +### Key Gotchas + +1. **Prisma schema requires manual relation fixes**: The `Bot` and `BotMessage` models reference `Workspace`, `Channel`, and `ChatMessage` but the reverse relation fields (`bots Bot[]`, `botMessages BotMessage[]`) must be present on those models. Run `npx prisma generate` after any schema changes. + +2. **`projectTemplates.json` required at startup**: The backend TemplateService throws at boot if `backend/config/projectTemplates.json` doesn't exist. A minimal seed file is committed. + +3. **Module DI for `JwtAuthGuard`**: Any NestJS module using `@UseGuards(JwtAuthGuard)` must import `AuthModule` (which exports `AuthService`). + +4. **`.env` location**: The backend reads environment from `backend/.env` (via `@nestjs/config`). The committed `env.development` uses Docker service hostnames; for local dev, create `.env` with `localhost` addresses (DATABASE_URL, REDIS_URL, etc.). + +5. **TypeScript checking**: `npm run build` runs `prisma generate && nest build`. For type-only checking use `npx tsc --noEmit` from the backend directory. + +6. **No ESLint configured**: The project does not have an ESLint config. TypeScript compilation (`tsc --noEmit`) is the primary static analysis. + +7. **MinIO/S3 and LiveKit are optional**: File vault and video meeting features require these services but the backend starts fine without them. + +### Test Account (local dev) + +``` +Email: dev@flowspace.app +Password: TestPass123! +``` + +Or register via `POST /api/v1/auth/register` with `{ email, password, name }`. + +### Flutter Client + +The Flutter client (`client_flutter/`) targets desktop (Windows primary) and mobile. It requires the Flutter SDK and cannot be run in headless Cloud Agent environments. Focus backend development on the NestJS API server. diff --git a/backend/config/projectTemplates.json b/backend/config/projectTemplates.json new file mode 100644 index 00000000..7935d460 --- /dev/null +++ b/backend/config/projectTemplates.json @@ -0,0 +1,39 @@ +{ + "version": "1.0.0", + "templates": [ + { + "id": "kanban", + "name": "Kanban Board", + "description": "Simple task management with columns: To Do, In Progress, Done", + "backgroundModule": "kanban", + "tools": ["tasks", "labels", "assignments"], + "defaultBoards": ["kanban"], + "defaultSettings": { + "columns": ["To Do", "In Progress", "Done"] + } + }, + { + "id": "storyboard", + "name": "Storyboard", + "description": "Visual storyboard for creative projects", + "backgroundModule": "storyboard", + "tools": ["scenes", "characters", "notes"], + "defaultBoards": ["storyboard"], + "defaultSettings": { + "layout": "grid" + } + }, + { + "id": "sprint", + "name": "Sprint Planning", + "description": "Agile sprint planning with backlog and sprint boards", + "backgroundModule": "agile", + "tools": ["tasks", "sprints", "velocity"], + "defaultBoards": ["backlog", "kanban"], + "defaultSettings": { + "sprintLength": 14, + "columns": ["Backlog", "To Do", "In Progress", "Review", "Done"] + } + } + ] +} diff --git a/backend/package-lock.json b/backend/package-lock.json index 4a279290..27d40c07 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -165,6 +165,23 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@angular-devkit/schematics-cli/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular-devkit/schematics-cli/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -183,6 +200,21 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/@angular-devkit/schematics-cli/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular-devkit/schematics-cli/node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -244,6 +276,23 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@angular-devkit/schematics/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular-devkit/schematics/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -262,6 +311,21 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/@angular-devkit/schematics/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular-devkit/schematics/node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -2164,6 +2228,23 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@nestjs/schematics/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@nestjs/schematics/node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -2182,6 +2263,21 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/@nestjs/schematics/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@nestjs/schematics/node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma index 03bc3ba9..cd3952a9 100644 --- a/backend/prisma/schema.prisma +++ b/backend/prisma/schema.prisma @@ -35,6 +35,7 @@ model Workspace { members WorkspaceMember[] channels Channel[] files VaultFile[] + bots Bot[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } @@ -66,6 +67,7 @@ model Channel { updatedAt DateTime @updatedAt workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade) messages ChatMessage[] + botMessages BotMessage[] } model ChatMessage { @@ -88,6 +90,7 @@ model ChatMessage { sender User @relation(fields: [senderId], references: [id]) parent ChatMessage? @relation("MessageThread", fields: [parentId], references: [id], onDelete: Cascade) replies ChatMessage[] @relation("MessageThread") + botMessages BotMessage[] @relation("BotMessageThread") @@index([parentId]) @@index([channelId, createdAt]) diff --git a/backend/src/bots/bots.module.ts b/backend/src/bots/bots.module.ts index 7d8b81f3..5d8e4b89 100644 --- a/backend/src/bots/bots.module.ts +++ b/backend/src/bots/bots.module.ts @@ -5,6 +5,7 @@ import { BotsService } from './bots.service'; import { BotsController } from './bots.controller'; import { BotsGateway } from './bots.gateway'; import { BotAuthGuard } from './bots-auth.guard'; +import { AuthModule } from '../auth/auth.module'; import { SharedModule } from '../shared/shared.module'; import { PrismaModule } from '../database/prisma.module'; @@ -13,6 +14,7 @@ import { PrismaModule } from '../database/prisma.module'; imports: [ PrismaModule, SharedModule, + AuthModule, JwtModule.registerAsync({ inject: [ConfigService], useFactory: (config: ConfigService) => ({ diff --git a/backend/src/bots/bots.service.ts b/backend/src/bots/bots.service.ts index f875590a..6fd4e77b 100644 --- a/backend/src/bots/bots.service.ts +++ b/backend/src/bots/bots.service.ts @@ -7,7 +7,7 @@ import { import { randomBytes, randomUUID } from 'crypto'; import { hash, compare } from 'bcrypt'; import { PrismaService } from '../database/prisma.service'; -import { WorkspaceRole } from '@prisma/client'; +import { WorkspaceRole, BotHandlerType } from '@prisma/client'; @Injectable() export class BotsService { @@ -190,7 +190,7 @@ export class BotsService { botId, command: data.command, description: data.description, - handlerType: (data.handlerType as any) || 'WEBSOCKET', + handlerType: (data.handlerType as BotHandlerType) || BotHandlerType.WEBSOCKET, handlerUrl: data.handlerUrl, }, }); @@ -223,7 +223,10 @@ export class BotsService { return this.prisma.botCommand.update({ where: { id: commandId }, - data, + data: { + ...data, + handlerType: data.handlerType ? (data.handlerType as BotHandlerType) : undefined, + }, }); } diff --git a/backend/src/bots/dto/bot.dto.ts b/backend/src/bots/dto/bot.dto.ts index 9e172c8d..da0f4aed 100644 --- a/backend/src/bots/dto/bot.dto.ts +++ b/backend/src/bots/dto/bot.dto.ts @@ -4,12 +4,12 @@ export class CreateBotDto { @IsString() @MinLength(1) @MaxLength(64) - name: string; + name!: string; @IsString() @MinLength(1) @MaxLength(128) - displayName: string; + displayName!: string; @IsOptional() @IsString() @@ -46,11 +46,11 @@ export class CreateCommandDto { @IsString() @MinLength(1) @MaxLength(64) - command: string; + command!: string; @IsString() @MaxLength(200) - description: string; + description!: string; @IsOptional() @IsString() @@ -84,5 +84,5 @@ export class SubscribeEventDto { @IsString() @MinLength(1) @MaxLength(64) - event: string; + event!: string; } diff --git a/backend/src/search/search.module.ts b/backend/src/search/search.module.ts index cb7ae91f..903180e6 100644 --- a/backend/src/search/search.module.ts +++ b/backend/src/search/search.module.ts @@ -1,12 +1,13 @@ import { Module } from '@nestjs/common'; +import { AuthModule } from '../auth/auth.module'; import { PrismaModule } from '../database/prisma.module'; import { SharedModule } from '../shared/shared.module'; import { SearchController } from './search.controller'; import { SearchService } from './search.service'; @Module({ - imports: [PrismaModule, SharedModule], + imports: [PrismaModule, SharedModule, AuthModule], controllers: [SearchController], providers: [SearchService], }) diff --git a/bot-sdk/package-lock.json b/bot-sdk/package-lock.json new file mode 100644 index 00000000..b58a52b5 --- /dev/null +++ b/bot-sdk/package-lock.json @@ -0,0 +1,141 @@ +{ + "name": "@flowspace/bot-sdk", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@flowspace/bot-sdk", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "socket.io-client": "^4.7.0" + }, + "devDependencies": { + "typescript": "^5.3.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io-client": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.4.tgz", + "integrity": "sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.18.3", + "xmlhttprequest-ssl": "~2.1.1" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/socket.io-client": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.3.tgz", + "integrity": "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1", + "engine.io-client": "~6.6.1", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.6.tgz", + "integrity": "sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz", + "integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==", + "engines": { + "node": ">=0.4.0" + } + } + } +} From ff3ab349e105aac83f19eb6c6858d832e521c6b2 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 15 May 2026 01:15:55 +0000 Subject: [PATCH 2/2] fix: address PR review feedback - Fix markdown lint violations in AGENTS.md (MD031 blank line before fence, MD040 language specifier) - Add proper enum validation for BotHandlerType in DTOs using @IsEnum decorator - Update service to accept BotHandlerType directly instead of casting from string - Simplify updateCommand by passing DTO data directly (now type-safe) Co-authored-by: RedWoodOG --- AGENTS.md | 3 ++- backend/src/bots/bots.service.ts | 11 ++++------- backend/src/bots/dto/bot.dto.ts | 9 +++++---- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 30be3597..8fa527e2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -22,6 +22,7 @@ - **Redis** on `localhost:6379` — used for Socket.IO horizontal scaling; backend gracefully falls back to in-memory adapter if unavailable Start services: + ```bash sudo pg_ctlcluster 16 main start sudo redis-server --daemonize yes @@ -45,7 +46,7 @@ sudo redis-server --daemonize yes ### Test Account (local dev) -``` +```text Email: dev@flowspace.app Password: TestPass123! ``` diff --git a/backend/src/bots/bots.service.ts b/backend/src/bots/bots.service.ts index 6fd4e77b..3d93b8ca 100644 --- a/backend/src/bots/bots.service.ts +++ b/backend/src/bots/bots.service.ts @@ -173,7 +173,7 @@ export class BotsService { workspaceId: string, botId: string, userId: string, - data: { command: string; description: string; handlerType?: string; handlerUrl?: string }, + data: { command: string; description: string; handlerType?: BotHandlerType; handlerUrl?: string }, ) { await this.requireAdmin(workspaceId, userId); await this.requireBotOwnership(workspaceId, botId); @@ -190,7 +190,7 @@ export class BotsService { botId, command: data.command, description: data.description, - handlerType: (data.handlerType as BotHandlerType) || BotHandlerType.WEBSOCKET, + handlerType: data.handlerType || BotHandlerType.WEBSOCKET, handlerUrl: data.handlerUrl, }, }); @@ -209,7 +209,7 @@ export class BotsService { botId: string, commandId: string, userId: string, - data: { description?: string; enabled?: boolean; handlerType?: string; handlerUrl?: string }, + data: { description?: string; enabled?: boolean; handlerType?: BotHandlerType; handlerUrl?: string }, ) { await this.requireAdmin(workspaceId, userId); await this.requireBotOwnership(workspaceId, botId); @@ -223,10 +223,7 @@ export class BotsService { return this.prisma.botCommand.update({ where: { id: commandId }, - data: { - ...data, - handlerType: data.handlerType ? (data.handlerType as BotHandlerType) : undefined, - }, + data, }); } diff --git a/backend/src/bots/dto/bot.dto.ts b/backend/src/bots/dto/bot.dto.ts index da0f4aed..02b341b0 100644 --- a/backend/src/bots/dto/bot.dto.ts +++ b/backend/src/bots/dto/bot.dto.ts @@ -1,4 +1,5 @@ import { IsString, IsOptional, IsBoolean, IsEnum, MaxLength, MinLength } from 'class-validator'; +import { BotHandlerType } from '@prisma/client'; export class CreateBotDto { @IsString() @@ -53,8 +54,8 @@ export class CreateCommandDto { description!: string; @IsOptional() - @IsString() - handlerType?: string; + @IsEnum(BotHandlerType) + handlerType?: BotHandlerType; @IsOptional() @IsString() @@ -72,8 +73,8 @@ export class UpdateCommandDto { enabled?: boolean; @IsOptional() - @IsString() - handlerType?: string; + @IsEnum(BotHandlerType) + handlerType?: BotHandlerType; @IsOptional() @IsString()