Organizing with Tags and Collections
To organize bookmarks in this system, you use Tags for labeling and Collections for grouping. These entities are managed through the BookmarkService, which coordinates updates between the BookmarkRepository and the application's search and cache layers.
Managing Tags
Tags are labels that can be attached to multiple bookmarks. You create and manage them using the BookmarkService, which ensures that tag names are validated and that deletions are propagated correctly.
Creating and Assigning Tags
To create a tag, provide a dictionary containing at least a name. You can also specify a color using the TagColor enum.
from app.services.bookmark_service import BookmarkService
from app.models.tag import TagColor
service = BookmarkService()
# Create a new tag
tag_data = {
"name": "Research",
"color": "blue",
"description": "Academic papers and articles"
}
tag, error = service.create_tag(tag_data)
if tag:
print(f"Created tag: {tag.id}")
To assign a tag to a bookmark, you update the bookmark's tags list. Note that the Bookmark model stores tag IDs, not the tag objects themselves.
# Assigning a tag to a bookmark via update
bookmark_id = "abc123"
service.update_bookmark(bookmark_id, {"tags": [tag.id]})
Updating and Deleting Tags
When you update a tag's name or color, the changes are persisted in the BookmarkRepository. Deleting a tag is a "heavy" operation because the service must strip the tag ID from every bookmark that uses it.
# Update a tag
service.update_tag(tag.id, {"color": "green", "name": "Deep Research"})
# Delete a tag (automatically removes it from all bookmarks)
success = service.delete_tag(tag.id)
The BookmarkService.delete_tag method performs the following cleanup:
- Retrieves all bookmarks containing the tag using
BookmarkRepository.get_bookmarks_with_tag. - Calls
bookmark.remove_tag(tag_id)on each. - Saves the updated bookmarks and invalidates their cache entries.
- Finally, removes the tag from the repository.
Grouping with Collections
Collections allow you to group bookmarks either manually or automatically via "Smart" rules.
Manual Collections
Manual collections require you to explicitly add or remove bookmarks.
# Create a manual collection
collection_data = {
"name": "Project Alpha",
"type": "manual"
}
collection, error = service.create_collection(collection_data)
# Add a bookmark to the collection
service.add_to_collection(collection.id, "bookmark_id_123")
# Remove a bookmark
service.remove_from_collection(collection.id, "bookmark_id_123")
Smart Collections
Smart collections use a filter_rule to automatically include bookmarks based on their title or description. You cannot manually add bookmarks to a smart collection.
# Create a smart collection for Python-related bookmarks
smart_data = {
"name": "Python Stuff",
"type": "smart",
"filter_rule": "python"
}
smart_collection, error = service.create_collection(smart_data)
# Check if it's smart
if smart_collection.is_smart:
print(f"Filter rule: {smart_collection.filter_rule}")
The Collection._apply_filter method is used internally to evaluate which bookmarks match the rule:
# Internal logic in app/models/collection.py
def _apply_filter(self, bookmarks: list) -> List[str]:
if not self.filter_rule:
return []
keyword = self.filter_rule.lower()
return [b.id for b in bookmarks if keyword in b.title.lower() or keyword in b.description.lower()]
Persistence and Constraints
The BookmarkRepository acts as the storage layer for these entities. Because it is an in-memory implementation, all tags and collections are lost when the application restarts.
Validation Rules
The system enforces several constraints defined in app/models/_validators.py and the model classes:
- Tag Names: Must be between 1 and 50 characters.
- Collection Names: Required and cannot be empty.
- Tag Colors: Must be one of the values in
TagColor(red,blue,green,yellow,purple,gray).
Troubleshooting
- Data Loss: Remember that
BookmarkRepositoryuses Python dictionaries (self._tags,self._collections). Data does not persist across sessions. - Smart Collection Errors: If you attempt to call
add_to_collectionon a collection wherecollection_typeisCollectionType.SMART, the operation will returnFalseand fail. - Performance: Deleting a tag that is used by thousands of bookmarks may be slow, as
BookmarkService.delete_tagiterates through all matching bookmarks to update them individually.