A social knowledge tool for researchers built on ATProto
1# Collection Text Search Feature
2
3## Overview
4
5Enable text search over a user's collections so they can quickly find and select existing collections when adding cards.
6
7## Implementation Options
8
9Based on our CQRS and DDD architecture patterns, we have several strategic approaches:
10
11### Option 1: Extend Existing Query Use Case (Recommended)
12
13**Pattern**: Enhance `GetMyCollectionsUseCase` with search capability
14
15**Pros**:
16
17- Follows single responsibility - still "getting collections"
18- Reuses existing pagination, sorting, and enrichment logic
19- Maintains consistent API surface
20- Simpler client-side implementation
21
22**Implementation**:
23
24```typescript
25// Update existing query interface
26export interface GetMyCollectionsQuery {
27 curatorId: string;
28 page?: number;
29 limit?: number;
30 sortBy?: CollectionSortField;
31 sortOrder?: SortOrder;
32 searchText?: string; // NEW: Optional search parameter
33}
34
35// Update repository interface
36export interface ICollectionQueryRepository {
37 findByCreator(
38 curatorId: string,
39 options: CollectionQueryOptions & { searchText?: string }, // Enhanced options
40 ): Promise<PaginatedQueryResult<CollectionQueryResultDTO>>;
41}
42```
43
44**Changes Required**:
45
46- Update `GetMyCollectionsQuery` interface
47- Update `ICollectionQueryRepository.findByCreator()` method signature
48- Update `DrizzleCollectionQueryRepository` implementation with text search logic
49- Update API client types and methods
50- Update HTTP controller to handle search parameter
51
52### Option 2: Dedicated Search Use Case
53
54**Pattern**: Create separate `SearchMyCollectionsUseCase`
55
56**Pros**:
57
58- Clear separation of concerns
59- Optimized specifically for search scenarios
60- Can implement different search algorithms/ranking
61- Easier to add search-specific features (highlighting, relevance scoring)
62
63**Implementation**:
64
65```typescript
66// New dedicated use case
67export interface SearchMyCollectionsQuery {
68 curatorId: string;
69 searchText: string; // Required for search
70 page?: number;
71 limit?: number;
72}
73
74export interface SearchMyCollectionsResult {
75 collections: CollectionSearchResultDTO[]; // Could include relevance scores
76 pagination: PaginationInfo;
77 searchMetadata: {
78 query: string;
79 totalMatches: number;
80 searchTime?: number;
81 };
82}
83```
84
85**Changes Required**:
86
87- Create new `SearchMyCollectionsUseCase`
88- Create new repository method or separate search repository
89- Create new HTTP controller and route
90- Update API client with new search method
91- Implement search-specific DTOs
92
93### Option 3: Hybrid Approach
94
95**Pattern**: Extend existing use case but add dedicated search endpoint
96
97**Implementation**:
98
99- Keep enhanced `GetMyCollectionsUseCase` for general listing with optional search
100- Add dedicated `SearchMyCollectionsUseCase` for advanced search features
101- Both share the same underlying repository search capability
102
103## Recommended Approach: Option 1 (Extended Query)
104
105### Rationale
106
1071. **Consistency**: Aligns with existing patterns where query use cases handle filtering/searching
1082. **Simplicity**: Single endpoint for both listing and searching collections
1093. **Client Efficiency**: No need to switch between different API methods
1104. **Future-Proof**: Easy to add more filter parameters later
111
112### Implementation Plan
113
114#### 1. Domain Layer Updates
115
116```typescript
117// Update ICollectionQueryRepository interface
118export interface CollectionQueryOptions {
119 page: number;
120 limit: number;
121 sortBy: CollectionSortField;
122 sortOrder: SortOrder;
123 searchText?: string; // NEW
124}
125```
126
127#### 2. Application Layer Updates
128
129```typescript
130// Update GetMyCollectionsQuery
131export interface GetMyCollectionsQuery {
132 curatorId: string;
133 page?: number;
134 limit?: number;
135 sortBy?: CollectionSortField;
136 sortOrder?: SortOrder;
137 searchText?: string; // NEW
138}
139```
140
141#### 3. Infrastructure Layer Updates
142
143- Update `DrizzleCollectionQueryRepository.findByCreator()` to handle text search
144- Implement SQL text search (LIKE, full-text search, or similar)
145- Update HTTP controller to accept search parameter
146- Update route parameter handling
147
148#### 4. API Client Updates
149
150```typescript
151// Update existing types
152export interface GetMyCollectionsParams {
153 page?: number;
154 limit?: number;
155 sortBy?: string;
156 sortOrder?: 'asc' | 'desc';
157 searchText?: string; // NEW
158}
159
160// No new methods needed - existing getMyCollections() handles search
161```
162
163### Search Implementation Details
164
165#### Database Search Strategy
166
167```sql
168-- Example SQL for text search across name and description
169SELECT * FROM collections
170WHERE curator_id = ?
171 AND (
172 name ILIKE '%search_term%'
173 OR description ILIKE '%search_term%'
174 )
175ORDER BY name ASC
176LIMIT ? OFFSET ?;
177```
178
179#### Search Behavior
180
181- **Empty/null search**: Return all collections (existing behavior)
182- **Search scope**: Collection name and description fields
183- **Search type**: Case-insensitive partial matching (can be enhanced later)
184- **Sorting**: Maintain existing sort options, could add relevance sorting later
185
186### Migration Path
187
1881. Update domain interfaces (backward compatible)
1892. Update use case (backward compatible - search is optional)
1903. Update repository implementation
1914. Update HTTP layer
1925. Update API client types
1936. Update frontend components
194
195This approach provides immediate value while maintaining architectural consistency and leaving room for future enhancements like advanced search features, search analytics, or dedicated search optimization.