133 lines
4.4 KiB
TypeScript
133 lines
4.4 KiB
TypeScript
import {
|
|
Body,
|
|
Controller,
|
|
Delete,
|
|
Get,
|
|
HttpCode,
|
|
HttpStatus,
|
|
Param,
|
|
Patch,
|
|
Post,
|
|
Query,
|
|
} from '@nestjs/common';
|
|
import { ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger';
|
|
import { DiaryService, DiaryEntryResponse } from './diary.service';
|
|
import { DiaryExplorationService } from './diary-exploration.service';
|
|
import { FeelingCategoryService } from './feeling-category.service';
|
|
import { CreateDiaryEntryDto } from './dto/create-diary-entry.dto';
|
|
import { UpdateDiaryEntryDto } from './dto/update-diary-entry.dto';
|
|
import { QueryDiaryDto } from './dto/query-diary.dto';
|
|
import { PaginatedResponse } from '@common/pagination.dto';
|
|
import { FeelingCategory } from './entities/feeling-category.entity';
|
|
import type { FeelingTrendPoint } from '@life-platform/shared';
|
|
|
|
@ApiTags('Diary')
|
|
@Controller('diary')
|
|
export class DiaryController {
|
|
constructor(
|
|
private readonly diaryService: DiaryService,
|
|
private readonly explorationService: DiaryExplorationService,
|
|
private readonly feelingCategoryService: FeelingCategoryService,
|
|
) {}
|
|
|
|
// --- Static routes BEFORE :id param routes ---
|
|
|
|
@Get('trends')
|
|
@ApiOperation({ summary: 'Get feeling intensity trends over time' })
|
|
@ApiQuery({ name: 'days', required: false, description: 'Number of days to look back (default 30)' })
|
|
@ApiQuery({ name: 'category', required: false, description: 'Filter to specific feeling category' })
|
|
getTrends(
|
|
@Query('days') days?: string,
|
|
@Query('category') category?: string,
|
|
): Promise<FeelingTrendPoint[]> {
|
|
return this.diaryService.getFeelingTrends(
|
|
days ? parseInt(days, 10) : 30,
|
|
category,
|
|
);
|
|
}
|
|
|
|
@Get('correlations')
|
|
@ApiOperation({ summary: 'Get feeling correlations with other factors' })
|
|
@ApiQuery({ name: 'category', required: true, description: 'Feeling category to correlate' })
|
|
getCorrelations(@Query('category') category: string) {
|
|
return this.diaryService.getCorrelations(category);
|
|
}
|
|
|
|
@Get('feeling-categories')
|
|
@ApiOperation({ summary: 'List all feeling categories' })
|
|
getFeelingCategories(): Promise<FeelingCategory[]> {
|
|
return this.feelingCategoryService.findAll();
|
|
}
|
|
|
|
@Post('feeling-categories')
|
|
@ApiOperation({ summary: 'Create a custom feeling category' })
|
|
createFeelingCategory(
|
|
@Body() data: { slug: string; name: string; description: string; examples: string[] },
|
|
): Promise<FeelingCategory> {
|
|
return this.feelingCategoryService.create(data);
|
|
}
|
|
|
|
// --- CRUD routes ---
|
|
|
|
@Post()
|
|
@ApiOperation({ summary: 'Create diary entry (content encrypted at rest)' })
|
|
async createEntry(@Body() dto: CreateDiaryEntryDto): Promise<DiaryEntryResponse> {
|
|
const entry = await this.diaryService.create(dto);
|
|
|
|
if (dto.triggerExploration && entry.content) {
|
|
const needsExploration = await this.explorationService.detectNeedsExploration(entry.content);
|
|
if (needsExploration) {
|
|
const questions = await this.explorationService.generateQuestions(entry.content);
|
|
return {
|
|
...entry,
|
|
metadata: {
|
|
...(entry.metadata ?? {}),
|
|
pendingExploration: true,
|
|
explorationQuestions: questions,
|
|
},
|
|
};
|
|
}
|
|
}
|
|
|
|
return entry;
|
|
}
|
|
|
|
@Get()
|
|
@ApiOperation({ summary: 'List diary entries with filters' })
|
|
findAll(@Query() query: QueryDiaryDto): Promise<PaginatedResponse<DiaryEntryResponse>> {
|
|
return this.diaryService.findAll(query);
|
|
}
|
|
|
|
@Get(':id')
|
|
@ApiOperation({ summary: 'Get diary entry by ID (decrypted content)' })
|
|
findOne(@Param('id') id: string): Promise<DiaryEntryResponse> {
|
|
return this.diaryService.findOne(id);
|
|
}
|
|
|
|
@Post(':id/explore')
|
|
@ApiOperation({ summary: 'Trigger emotional exploration on an existing entry' })
|
|
async explore(@Param('id') id: string): Promise<{ questions: string[] }> {
|
|
const entry = await this.diaryService.findOne(id);
|
|
if (!entry.content) {
|
|
return { questions: [] };
|
|
}
|
|
const questions = await this.explorationService.generateQuestions(entry.content);
|
|
return { questions };
|
|
}
|
|
|
|
@Patch(':id')
|
|
@ApiOperation({ summary: 'Update diary entry' })
|
|
update(
|
|
@Param('id') id: string,
|
|
@Body() dto: UpdateDiaryEntryDto,
|
|
): Promise<DiaryEntryResponse> {
|
|
return this.diaryService.update(id, dto);
|
|
}
|
|
|
|
@Delete(':id')
|
|
@HttpCode(HttpStatus.NO_CONTENT)
|
|
@ApiOperation({ summary: 'Soft delete diary entry' })
|
|
remove(@Param('id') id: string): Promise<void> {
|
|
return this.diaryService.softRemove(id);
|
|
}
|
|
}
|