diff --git a/apps/client/src/features/search/components/search-spotlight.tsx b/apps/client/src/features/search/components/search-spotlight.tsx
index 725f8d51..1a5d89a6 100644
--- a/apps/client/src/features/search/components/search-spotlight.tsx
+++ b/apps/client/src/features/search/components/search-spotlight.tsx
@@ -1,6 +1,6 @@
import { Spotlight } from "@mantine/spotlight";
import { IconSearch } from "@tabler/icons-react";
-import { Group, VisuallyHidden } from "@mantine/core";
+import { Group, Text, VisuallyHidden } from "@mantine/core";
import { useState, useMemo } from "react";
import { useDebouncedValue } from "@mantine/hooks";
import { useTranslation } from "react-i18next";
@@ -84,6 +84,11 @@ export function SearchSpotlight({ spaceId }: SearchSpotlightProps) {
onFiltersChange={handleFiltersChange}
spaceId={spaceId}
/>
+ {/* #529: operator hint — matches ANY word by default; "…" for an exact
+ phrase, +term to require, -term to exclude. */}
+
+ {t('Tip: "exact phrase", +required, -excluded')}
+
diff --git a/apps/client/src/features/search/types/search.types.ts b/apps/client/src/features/search/types/search.types.ts
index 5aa3195b..453e1535 100644
--- a/apps/client/src/features/search/types/search.types.ts
+++ b/apps/client/src/features/search/types/search.types.ts
@@ -5,6 +5,9 @@ import { IPage } from "@/features/page/types/page.types.ts";
export interface IPageSearch {
id: string;
+ // #529 A7 superset: `pageId` aliases `id`; `rank`/`highlight` are null for
+ // substring-only hits (the UI already falls back to the title/snippet).
+ pageId?: string;
title: string;
icon: string;
parentPageId: string;
@@ -12,9 +15,36 @@ export interface IPageSearch {
creatorId: string;
createdAt: Date;
updatedAt: Date;
- rank: string;
- highlight: string;
+ rank: string | number | null;
+ highlight: string | null;
space: Partial;
+ // New #529 fields (present from the native Postgres search driver).
+ snippet?: string;
+ score?: number;
+ path?: string[];
+ matchedFields?: string[];
+ matchedTerms?: string[];
+}
+
+// #529 A5 pagination envelope returned by POST /search (native driver). The web
+// list helpers read `items`; these travel alongside for pagination + diagnostics.
+export interface IPageSearchResponse {
+ items: IPageSearch[];
+ total: number;
+ hasMore: boolean;
+ truncatedAtCap: boolean;
+ offset: number;
+ query?: {
+ raw: string;
+ parsed: {
+ positive: string[];
+ required: string[];
+ excluded: string[];
+ reason?: string;
+ };
+ mode: "or" | "and";
+ match: string;
+ };
}
export interface SearchSuggestionParams {
@@ -37,6 +67,10 @@ export interface IPageSearchParams {
query: string;
spaceId?: string;
shareId?: string;
+ // #529 A9: match mode (auto default) + pagination.
+ match?: "auto" | "word" | "prefix" | "substring";
+ limit?: number;
+ offset?: number;
}
export interface IAttachmentSearch {