Skip to main content

Organizing with Tags and Collections

To manage metadata and group bookmarks in this project, you use the BookmarkService from app.services.bookmark_service. This service acts as a central facade that coordinates operations across the repository, search index, and cache to ensure data consistency.

Managing Tags

Tags are labels used to categorize bookmarks. The BookmarkService handles tag lifecycle and ensures that deleting a tag also removes it from all associated bookmarks.

Creating and Updating Tags

You can create a tag by providing a name and an optional color from the TagColor enum defined in app.models.tag.

from app.services.bookmark_service import BookmarkService
from app.models.tag import TagColor

service = BookmarkService()

# Create a new tag
tag_data = {
"name": "Research",
"color": TagColor.BLUE.value,
"description": "Academic papers and articles"
}
tag, error = service.create_tag(tag_data)

if error:
print(f"Failed to create tag: {error}")

# Update an existing tag
update_data = {"color": TagColor.GREEN.value}
updated_tag, error = service.update_tag(tag.id, update_data)

Deleting Tags and Automatic Stripping

When you delete a tag using delete_tag, the service automatically iterates through every bookmark associated with that tag to remove the reference. This ensures that no bookmark points to a non-existent tag.

# This operation strips the tag from all bookmarks before deleting the tag itself
success = service.delete_tag("tag_id_123")

if not success:
print("Tag not found")

The internal logic in app/services/bookmark_service.py performs the following steps during deletion:

  1. Retrieves the tag from the repository.
  2. Fetches all bookmarks containing that tag_id.
  3. Calls bookmark.remove_tag(tag_id) on each.
  4. Saves the updated bookmark and invalidates its cache entry.
  5. Finally, deletes the tag from the repository.

Grouping with Collections

Collections allow you to group bookmarks either manually or automatically via "smart" filters.

Creating Collections

Collections are created via create_collection. You can specify the type as manual (default) or smart.

# Create a manual collection
manual_data = {"name": "Project Alpha", "type": "manual"}
collection, error = service.create_collection(manual_data)

# Create a smart collection with a filter rule
smart_data = {
"name": "Python Docs",
"type": "smart",
"filter_rule": "python"
}
smart_collection, error = service.create_collection(smart_data)

Managing Manual Membership

For manual collections, you use add_to_collection and remove_from_collection to manage the bookmark_ids list.

# Add a bookmark to a collection
success = service.add_to_collection("collection_id_abc", "bookmark_id_789")

# Remove a bookmark from a collection
success = service.remove_from_collection("collection_id_abc", "bookmark_id_789")

Note that add_to_collection will return False if the collection is a "smart" collection, as membership in smart collections is determined by the filter_rule rather than manual assignment.

Maintaining Data Consistency

The BookmarkService ensures that any change to metadata is reflected across the entire system. When a bookmark is updated (e.g., when a tag is removed or the bookmark is added to a collection), the service:

  1. Persists the change via BookmarkRepository.
  2. Updates the SearchIndex so the change is searchable.
  3. Invalidates the LRUCache entry for that bookmark to ensure subsequent reads fetch the fresh data.

Troubleshooting and Limitations

  • Tag Deletion Performance: Deleting a tag is an O(N) operation, where N is the number of bookmarks using that tag. For tags with thousands of bookmarks, this may cause a delay as the service must update and re-index each bookmark individually.
  • Smart Collection Updates: While the Collection model in app/models/collection.py includes an internal _apply_filter method, the BookmarkService currently focuses on managing the bookmark_ids list for manual collections. Smart collections are primarily used for UI filtering based on the filter_rule.
  • Soft Deletion: The delete_bookmark method in BookmarkService performs a "soft delete" by moving the bookmark to the trash (via bookmark.trash()) rather than removing it from the database entirely. Use restore_bookmark to bring it back.