Domain Model Architecture
The domain model architecture of this system is built around three primary entities: Bookmarks, Tags, and Collections. These entities are implemented as Python dataclasses in the app/models/ directory, providing a clean separation between data structure and business logic.
The Bookmark Entity
The Bookmark class (found in app/models/bookmark.py) is the central entity of the system. It represents a saved URL along with its associated metadata.
State and Lifecycle
Bookmarks use the BookmarkStatus enum to manage their visibility and lifecycle:
ACTIVE: The default state for new bookmarks.ARCHIVED: For bookmarks that are saved but no longer in active use.TRASHED: A soft-delete state.
The entity tracks its own modification state using a _touch() helper, which updates the updated_at timestamp whenever a state change occurs (e.g., archiving, trashing, or modifying tags).
# app/models/bookmark.py
def archive(self) -> None:
"""Move the bookmark to the archive."""
self.status = BookmarkStatus.ARCHIVED
self._touch()
def _touch(self) -> None:
"""Update the modification timestamp."""
self.updated_at = datetime.utcnow()
Identification
Bookmarks are identified by a 12-character hex UUID, generated automatically upon instantiation:
id: str = field(default_factory=lambda: uuid.uuid4().hex[:12])
Tags and Categorization
Tags provide a flexible, many-to-many categorization system. The relationship is managed by storing a list of Tag IDs directly on the Bookmark entity.
The Tag Entity
The Tag class (app/models/tag.py) includes:
- Metadata: A name, a
TagColorenum (e.g.,RED,BLUE,GREEN), and an optional description. - Usage Tracking: A
usage_countinteger that is incremented or decremented as the tag is attached to or removed from bookmarks. - Identification: An 8-character hex UUID.
Relationship Management
While the Bookmark entity provides methods like add_tag(tag_id) and remove_tag(tag_id), the BookmarkService orchestrates the integrity of these relationships. For example, when a tag is deleted, the service ensures it is stripped from all bookmarks before the tag itself is removed from the repository.
# app/services/bookmark_service.py
def delete_tag(self, tag_id: str) -> bool:
"""Delete a tag and strip it from all bookmarks."""
tag = self._repo.get_tag(tag_id)
if not tag:
return False
for bookmark in self._repo.get_bookmarks_with_tag(tag_id):
bookmark.remove_tag(tag_id)
self._repo.save_bookmark(bookmark)
self._cache.invalidate(bookmark.id)
self._repo.delete_tag(tag_id)
return True
Collections and Grouping
Collections (app/models/collection.py) allow users to group bookmarks. They are identified by a 10-character hex UUID. There are two distinct types of collections defined by the CollectionType enum:
Manual Collections
In a MANUAL collection, bookmarks are explicitly added or removed by the user. The collection maintains an ordered list of bookmark_ids.
Smart Collections
A SMART collection automatically populates itself based on a filter_rule. The _apply_filter method evaluates this rule against bookmark metadata (currently checking if a keyword exists in the title or description).
# app/models/collection.py
def _apply_filter(self, bookmarks: list) -> List[str]:
"""Evaluate the filter_rule against a list of bookmarks."""
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()]
Service Layer Orchestration
The BookmarkService (app/services/bookmark_service.py) acts as a facade over the domain models and the repository. It is responsible for:
- Instantiation: Using
from_dictmethods to create entities from raw request data. - Validation: Ensuring URLs and titles meet system requirements before persistence.
- Cross-Entity Logic: Managing the side effects of operations, such as updating the
SearchIndexor invalidating theLRUCachewhen a bookmark is modified.
This architecture ensures that the domain models remain focused on data structure and internal state transitions, while the service layer handles the complexities of system-wide data integrity.