A social knowledge tool for researchers built on ATProto
Collection Text Search Feature#
Overview#
Enable text search over a user's collections so they can quickly find and select existing collections when adding cards.
Implementation Options#
Based on our CQRS and DDD architecture patterns, we have several strategic approaches:
Option 1: Extend Existing Query Use Case (Recommended)#
Pattern: Enhance GetMyCollectionsUseCase with search capability
Pros:
- Follows single responsibility - still "getting collections"
- Reuses existing pagination, sorting, and enrichment logic
- Maintains consistent API surface
- Simpler client-side implementation
Implementation:
// Update existing query interface
export interface GetMyCollectionsQuery {
curatorId: string;
page?: number;
limit?: number;
sortBy?: CollectionSortField;
sortOrder?: SortOrder;
searchText?: string; // NEW: Optional search parameter
}
// Update repository interface
export interface ICollectionQueryRepository {
findByCreator(
curatorId: string,
options: CollectionQueryOptions & { searchText?: string }, // Enhanced options
): Promise<PaginatedQueryResult<CollectionQueryResultDTO>>;
}
Changes Required:
- Update
GetMyCollectionsQueryinterface - Update
ICollectionQueryRepository.findByCreator()method signature - Update
DrizzleCollectionQueryRepositoryimplementation with text search logic - Update API client types and methods
- Update HTTP controller to handle search parameter
Option 2: Dedicated Search Use Case#
Pattern: Create separate SearchMyCollectionsUseCase
Pros:
- Clear separation of concerns
- Optimized specifically for search scenarios
- Can implement different search algorithms/ranking
- Easier to add search-specific features (highlighting, relevance scoring)
Implementation:
// New dedicated use case
export interface SearchMyCollectionsQuery {
curatorId: string;
searchText: string; // Required for search
page?: number;
limit?: number;
}
export interface SearchMyCollectionsResult {
collections: CollectionSearchResultDTO[]; // Could include relevance scores
pagination: PaginationInfo;
searchMetadata: {
query: string;
totalMatches: number;
searchTime?: number;
};
}
Changes Required:
- Create new
SearchMyCollectionsUseCase - Create new repository method or separate search repository
- Create new HTTP controller and route
- Update API client with new search method
- Implement search-specific DTOs
Option 3: Hybrid Approach#
Pattern: Extend existing use case but add dedicated search endpoint
Implementation:
- Keep enhanced
GetMyCollectionsUseCasefor general listing with optional search - Add dedicated
SearchMyCollectionsUseCasefor advanced search features - Both share the same underlying repository search capability
Recommended Approach: Option 1 (Extended Query)#
Rationale#
- Consistency: Aligns with existing patterns where query use cases handle filtering/searching
- Simplicity: Single endpoint for both listing and searching collections
- Client Efficiency: No need to switch between different API methods
- Future-Proof: Easy to add more filter parameters later
Implementation Plan#
1. Domain Layer Updates#
// Update ICollectionQueryRepository interface
export interface CollectionQueryOptions {
page: number;
limit: number;
sortBy: CollectionSortField;
sortOrder: SortOrder;
searchText?: string; // NEW
}
2. Application Layer Updates#
// Update GetMyCollectionsQuery
export interface GetMyCollectionsQuery {
curatorId: string;
page?: number;
limit?: number;
sortBy?: CollectionSortField;
sortOrder?: SortOrder;
searchText?: string; // NEW
}
3. Infrastructure Layer Updates#
- Update
DrizzleCollectionQueryRepository.findByCreator()to handle text search - Implement SQL text search (LIKE, full-text search, or similar)
- Update HTTP controller to accept search parameter
- Update route parameter handling
4. API Client Updates#
// Update existing types
export interface GetMyCollectionsParams {
page?: number;
limit?: number;
sortBy?: string;
sortOrder?: 'asc' | 'desc';
searchText?: string; // NEW
}
// No new methods needed - existing getMyCollections() handles search
Search Implementation Details#
Database Search Strategy#
-- Example SQL for text search across name and description
SELECT * FROM collections
WHERE curator_id = ?
AND (
name ILIKE '%search_term%'
OR description ILIKE '%search_term%'
)
ORDER BY name ASC
LIMIT ? OFFSET ?;
Search Behavior#
- Empty/null search: Return all collections (existing behavior)
- Search scope: Collection name and description fields
- Search type: Case-insensitive partial matching (can be enhanced later)
- Sorting: Maintain existing sort options, could add relevance sorting later
Migration Path#
- Update domain interfaces (backward compatible)
- Update use case (backward compatible - search is optional)
- Update repository implementation
- Update HTTP layer
- Update API client types
- Update frontend components
This approach provides immediate value while maintaining architectural consistency and leaving room for future enhancements like advanced search features, search analytics, or dedicated search optimization.