Skip to main content

Managing Bookmark States

To manage the lifecycle of a bookmark in this system, you use the Bookmark model's state transition methods in conjunction with the BookmarkService to ensure changes are persisted and the cache is invalidated.

Transitioning Bookmark States

The most common way to change a bookmark's state is through the BookmarkService. This handles retrieving the object, calling the appropriate transition method, and updating the repository and cache.

from app.services.bookmark_service import BookmarkService

service = BookmarkService()
bookmark_id = "a1b2c3d4e5f6"

# 1. Archive a bookmark
archived_bookmark = service.archive_bookmark(bookmark_id)

# 2. Soft-delete (Trash) a bookmark
# Note: delete_bookmark in the service layer performs a soft-delete
success = service.delete_bookmark(bookmark_id)

# 3. Restore a bookmark to ACTIVE status
restored_bookmark = service.restore_bookmark(bookmark_id)

Understanding Bookmark States

The BookmarkStatus enum (defined in app/models/bookmark.py) defines three possible visibility states:

  • ACTIVE: The default state for new bookmarks.
  • ARCHIVED: For bookmarks that are no longer needed in the main view but should be kept.
  • TRASHED: For bookmarks marked for deletion (soft-delete).

The Bookmark class provides internal methods to transition between these states. Each method automatically calls _touch() to update the updated_at timestamp.

# Internal transitions within app/models/bookmark.py
def archive(self) -> None:
self.status = BookmarkStatus.ARCHIVED
self._touch()

def trash(self) -> None:
self.status = BookmarkStatus.TRASHED
self._touch()

def restore(self) -> None:
self.status = BookmarkStatus.ACTIVE
self._touch()

Filtering Bookmarks by Status

When listing bookmarks, you can filter by their current status using the list_bookmarks method in the service layer.

from app.models.bookmark import BookmarkStatus

service = BookmarkService()

# List only archived bookmarks
archived_list, total = service.list_bookmarks(status=BookmarkStatus.ARCHIVED.value)

# List only trashed bookmarks
trash_list, total = service.list_bookmarks(status=BookmarkStatus.TRASHED.value)

Serialization and State

When converting a bookmark to a dictionary for API responses, the status is converted to its string value.

# Serializing a bookmark
bookmark_data = bookmark.to_dict()
# Result: { ..., "status": "archived", ... }

# Creating a bookmark from a dictionary
# Note: from_dict defaults to BookmarkStatus.ACTIVE
new_bookmark = Bookmark.from_dict({
"url": "https://example.com",
"title": "Example"
})

Troubleshooting and Gotchas

Soft-delete vs. Hard-delete

There is a distinction between "deleting" in the service layer versus the repository layer:

  • Service Layer (BookmarkService.delete_bookmark): Performs a soft-delete by moving the bookmark to the TRASHED state.
  • Repository Layer (BookmarkRepository.delete_bookmark): Performs a hard-delete, completely removing the bookmark from the underlying storage.

Always use the BookmarkService unless you intend to permanently purge the data.

from_dict Limitations

The Bookmark.from_dict method is designed for creating new bookmarks from user input. It only extracts url, title, description, and tags. It does not restore the id, status, or timestamps from the dictionary. If you need to reconstruct a full bookmark object from stored data, you must manually assign these fields or use the repository's internal loading mechanisms.

# from_dict only handles these fields:
bookmark = Bookmark.from_dict(data)
# bookmark.status will ALWAYS be BookmarkStatus.ACTIVE regardless of data["status"]