feat(cc-053): DecisionsController — log decizii

This commit is contained in:
admin-valentin 2026-08-01 10:43:34 +00:00
parent b0415c6e76
commit ae7b1d63b1

View file

@ -1,34 +1,92 @@
import { Body, Controller, Get, Param, ParseUUIDPipe, Patch, Post } from '@nestjs/common';
import { Body, Controller, Get, Param, Patch, Post, Query } from '@nestjs/common';
import { IsArray, IsOptional, IsString } from 'class-validator';
import { and, desc, eq, isNull, isNotNull, lte } from 'drizzle-orm';
import { CurrentSession } from '../auth/session.decorator';
import type { AuthenticatedSession } from '../auth/tenant.guard';
import { CreateDecisionDto, UpdateDecisionDto } from './dto';
import { DecisionsService } from './decisions.service';
import { db } from '../db/client';
import { decisions } from '../db/schema';
class CreateDecisionDto {
@IsString() context: string;
@IsOptional() @IsArray() options?: string[];
@IsOptional() @IsArray() assumptions?: string[];
@IsOptional() @IsString() workspaceId?: string;
@IsOptional() @IsString() reviewDueAt?: string;
}
class UpdateDecisionDto {
@IsOptional() @IsString() selectedOption?: string;
@IsOptional() @IsString() outcomeReview?: string;
@IsOptional() @IsArray() evidence?: unknown[];
}
@Controller('decisions')
export class DecisionsController {
constructor(private readonly decisionsService: DecisionsService) {}
@Get()
list(@CurrentSession() session: AuthenticatedSession) {
return this.decisionsService.list(session);
async list(
@CurrentSession() session: AuthenticatedSession,
@Query('limit') limitStr?: string,
) {
const limit = Math.min(Math.max(1, parseInt(limitStr ?? '50', 10) || 50), 200);
return db.query.decisions.findMany({
where: eq(decisions.tenantId, session.tenantId),
orderBy: [desc(decisions.createdAt)],
limit,
});
}
@Get(':id')
getById(@CurrentSession() session: AuthenticatedSession, @Param('id', ParseUUIDPipe) id: string) {
return this.decisionsService.getById(session, id);
@Get('pending-review')
async pendingReview(@CurrentSession() session: AuthenticatedSession) {
const now = new Date();
return db.query.decisions.findMany({
where: and(
eq(decisions.tenantId, session.tenantId),
isNotNull(decisions.reviewDueAt),
lte(decisions.reviewDueAt, now),
isNull(decisions.outcomeReview),
),
orderBy: [desc(decisions.reviewDueAt)],
limit: 20,
});
}
@Post()
create(@CurrentSession() session: AuthenticatedSession, @Body() dto: CreateDecisionDto) {
return this.decisionsService.create(session, dto);
async create(
@CurrentSession() session: AuthenticatedSession,
@Body() dto: CreateDecisionDto,
) {
const [created] = await db
.insert(decisions)
.values({
tenantId: session.tenantId,
workspaceId: dto.workspaceId ?? null,
ownerUserId: session.userId,
context: dto.context,
options: dto.options ?? [],
assumptions: dto.assumptions ?? [],
evidence: [],
reviewDueAt: dto.reviewDueAt ? new Date(dto.reviewDueAt) : null,
})
.returning();
return created;
}
@Patch(':id')
update(
async update(
@CurrentSession() session: AuthenticatedSession,
@Param('id', ParseUUIDPipe) id: string,
@Param('id') id: string,
@Body() dto: UpdateDecisionDto,
) {
return this.decisionsService.update(session, id, dto);
const [updated] = await db
.update(decisions)
.set({
...(dto.selectedOption !== undefined ? { selectedOption: dto.selectedOption } : {}),
...(dto.outcomeReview !== undefined ? { outcomeReview: dto.outcomeReview } : {}),
...(dto.evidence !== undefined ? { evidence: dto.evidence } : {}),
updatedAt: new Date(),
})
.where(and(eq(decisions.id, id), eq(decisions.tenantId, session.tenantId)))
.returning();
return updated;
}
}