import { Controller, Get, Query, UseGuards } from "@nestjs/common"; import { SearchService, PaginatedSearchResults } from "./services/search.service"; import { SearchQueryDto, TagSearchDto, RecentEntriesDto } from "./dto"; import { AuthGuard } from "../auth/guards/auth.guard"; import { WorkspaceGuard, PermissionGuard } from "../common/guards"; import { Workspace, Permission, RequirePermission } from "../common/decorators"; import type { PaginatedEntries, KnowledgeEntryWithTags, } from "./entities/knowledge-entry.entity"; /** * Response for recent entries endpoint */ interface RecentEntriesResponse { data: KnowledgeEntryWithTags[]; count: number; } /** * Controller for knowledge search endpoints * All endpoints require authentication and workspace context */ @Controller("knowledge/search") @UseGuards(AuthGuard, WorkspaceGuard, PermissionGuard) export class SearchController { constructor(private readonly searchService: SearchService) {} /** * GET /api/knowledge/search * Full-text search across knowledge entries * Searches title and content with relevance ranking * Requires: Any workspace member * * @query q - The search query string (required) * @query status - Filter by entry status (optional) * @query page - Page number (default: 1) * @query limit - Results per page (default: 20, max: 100) */ @Get() @RequirePermission(Permission.WORKSPACE_ANY) async search( @Workspace() workspaceId: string, @Query() query: SearchQueryDto ): Promise { return this.searchService.search(query.q, workspaceId, { status: query.status, page: query.page, limit: query.limit, }); } /** * GET /api/knowledge/search/by-tags * Search entries by tags (entries must have ALL specified tags) * Requires: Any workspace member * * @query tags - Comma-separated list of tag slugs (required) * @query status - Filter by entry status (optional) * @query page - Page number (default: 1) * @query limit - Results per page (default: 20, max: 100) */ @Get("by-tags") @RequirePermission(Permission.WORKSPACE_ANY) async searchByTags( @Workspace() workspaceId: string, @Query() query: TagSearchDto ): Promise { return this.searchService.searchByTags(query.tags, workspaceId, { status: query.status, page: query.page, limit: query.limit, }); } /** * GET /api/knowledge/search/recent * Get recently modified entries * Requires: Any workspace member * * @query limit - Maximum number of entries (default: 10, max: 50) * @query status - Filter by entry status (optional) */ @Get("recent") @RequirePermission(Permission.WORKSPACE_ANY) async recentEntries( @Workspace() workspaceId: string, @Query() query: RecentEntriesDto ): Promise { const entries = await this.searchService.recentEntries( workspaceId, query.limit || 10, query.status ); return { data: entries, count: entries.length, }; } }