import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Inject, NotFoundException, Param, Patch, Post, UseGuards, } from '@nestjs/common'; import type { Brain } from '@mosaicstack/brain'; import { BRAIN } from '../brain/brain.tokens.js'; import { AuthGuard } from '../auth/auth.guard.js'; import { CurrentUser } from '../auth/current-user.decorator.js'; import { CreateMissionDto, UpdateMissionDto, CreateMissionTaskDto, UpdateMissionTaskDto, } from './missions.dto.js'; @Controller('api/missions') @UseGuards(AuthGuard) export class MissionsController { constructor(@Inject(BRAIN) private readonly brain: Brain) {} // ── Missions CRUD (user-scoped) ── @Get() async list(@CurrentUser() user: { id: string }) { return this.brain.missions.findAllByUser(user.id); } @Get(':id') async findOne(@Param('id') id: string, @CurrentUser() user: { id: string }) { const mission = await this.brain.missions.findByIdAndUser(id, user.id); if (!mission) throw new NotFoundException('Mission not found'); return mission; } @Post() async create(@Body() dto: CreateMissionDto, @CurrentUser() user: { id: string }) { return this.brain.missions.create({ name: dto.name, description: dto.description, projectId: dto.projectId, userId: user.id, phase: dto.phase, milestones: dto.milestones, config: dto.config, status: dto.status, }); } @Patch(':id') async update( @Param('id') id: string, @Body() dto: UpdateMissionDto, @CurrentUser() user: { id: string }, ) { const existing = await this.brain.missions.findByIdAndUser(id, user.id); if (!existing) throw new NotFoundException('Mission not found'); const mission = await this.brain.missions.update(id, dto); if (!mission) throw new NotFoundException('Mission not found'); return mission; } @Delete(':id') @HttpCode(HttpStatus.NO_CONTENT) async remove(@Param('id') id: string, @CurrentUser() user: { id: string }) { const existing = await this.brain.missions.findByIdAndUser(id, user.id); if (!existing) throw new NotFoundException('Mission not found'); const deleted = await this.brain.missions.remove(id); if (!deleted) throw new NotFoundException('Mission not found'); } // ── Mission Tasks sub-routes ── @Get(':missionId/tasks') async listTasks(@Param('missionId') missionId: string, @CurrentUser() user: { id: string }) { const mission = await this.brain.missions.findByIdAndUser(missionId, user.id); if (!mission) throw new NotFoundException('Mission not found'); return this.brain.missionTasks.findByMissionAndUser(missionId, user.id); } @Get(':missionId/tasks/:taskId') async getTask( @Param('missionId') missionId: string, @Param('taskId') taskId: string, @CurrentUser() user: { id: string }, ) { const mission = await this.brain.missions.findByIdAndUser(missionId, user.id); if (!mission) throw new NotFoundException('Mission not found'); const task = await this.brain.missionTasks.findByIdAndUser(taskId, user.id); if (!task) throw new NotFoundException('Mission task not found'); return task; } @Post(':missionId/tasks') async createTask( @Param('missionId') missionId: string, @Body() dto: CreateMissionTaskDto, @CurrentUser() user: { id: string }, ) { const mission = await this.brain.missions.findByIdAndUser(missionId, user.id); if (!mission) throw new NotFoundException('Mission not found'); return this.brain.missionTasks.create({ missionId, taskId: dto.taskId, userId: user.id, status: dto.status, description: dto.description, notes: dto.notes, pr: dto.pr, }); } @Patch(':missionId/tasks/:taskId') async updateTask( @Param('missionId') missionId: string, @Param('taskId') taskId: string, @Body() dto: UpdateMissionTaskDto, @CurrentUser() user: { id: string }, ) { const mission = await this.brain.missions.findByIdAndUser(missionId, user.id); if (!mission) throw new NotFoundException('Mission not found'); const existing = await this.brain.missionTasks.findByIdAndUser(taskId, user.id); if (!existing) throw new NotFoundException('Mission task not found'); const updated = await this.brain.missionTasks.update(taskId, dto); if (!updated) throw new NotFoundException('Mission task not found'); return updated; } @Delete(':missionId/tasks/:taskId') @HttpCode(HttpStatus.NO_CONTENT) async removeTask( @Param('missionId') missionId: string, @Param('taskId') taskId: string, @CurrentUser() user: { id: string }, ) { const mission = await this.brain.missions.findByIdAndUser(missionId, user.id); if (!mission) throw new NotFoundException('Mission not found'); const existing = await this.brain.missionTasks.findByIdAndUser(taskId, user.id); if (!existing) throw new NotFoundException('Mission task not found'); const deleted = await this.brain.missionTasks.remove(taskId); if (!deleted) throw new NotFoundException('Mission task not found'); } }