🔍 Filters Module
📖 Overview
The Filters module provides dynamic saved filter management for CRM entities (contacts, people, businesses, deals). Users can create custom filter criteria, save them for reuse, share them with teams, and see real-time counts of matching records. This enables sophisticated data segmentation and quick access to frequently-used contact/deal subsets.
File Path: internal/api/v1/filters/
Key Features
- Custom Filters: Define complex filter criteria with multiple conditions
- Real-time Counts: Live counts of matching records for each filter
- Team Sharing: Public filters visible to entire account team
- Default Filters: System-provided filters (All, Unassigned, etc.)
- Type Support: Contacts, People, Businesses, Deals
- Owner Permissions: Only filter creators or admins can edit
🗄️ Collections Used
filters
- Purpose: Store saved filter definitions
- Model:
shared/models/filter.js - Key Fields:
account(ObjectId) - Owner accountuser(ObjectId) - Creator usertype(String) - 'contacts' | 'people' | 'businesses' | 'deal'title(String) - Filter display namefilter(Object) - Filter criteria JSONis_public(Boolean) - Shared with teamis_default(Boolean) - System-provided filter (immutable)
Filter Criteria Structure:
{
type: 'contacts',
conditions: [
{ field: 'city', operator: 'equals', value: 'New York' },
{ field: 'created_at', operator: 'gt', value: '2025-01-01' }
],
logic: 'AND' // or 'OR'
}
crm.contacts
- Operations: Count, Query (via countProvider)
- Usage: Execute filter queries and count matching contacts
crm.deals
- Operations: Count, Query (via countProvider)
- Usage: Execute filter queries and count matching deals
🔧 Service Functions
File: Services/filter.js
get({ accountID, userID, type, pipeline, is_owner })
Retrieves all filters for a user/account with real-time counts.
Returns:
{
success: true,
data: [
{
id: ObjectId,
title: 'New York Contacts',
type: 'contacts',
filter: { ... },
count: 145, // Real-time count
is_public: true,
allow_update: false, // true if user is creator
user: ObjectId
}
]
}
Business Logic:
- Fetches user's personal filters + public team filters
- Calculates live counts via
countProvider.contactFilters()orcountProvider.dealFilters() - Sets
allow_update: trueonly for filter creator - Respects
is_ownerand pipeline permissions
post({ accountID, userID, type, title, filter, isPublic, is_owner, role })
Creates a new saved filter.
Validation:
- Only owners/admins can create public filters
- Filter criteria must be valid JSON
- Type must be one of: 'contacts', 'people', 'businesses', 'deal'
Returns: Created filter with initial count
put({ accountID, userID, filter, title, filterID, isPublic })
Updates existing filter or creates new one if updating default filter.
Special Handling:
if (filterData.is_default) {
// Cannot modify default filters - create new copy instead
savedData = await FilterModel.add(accountID, userID, type, filter, title, isPublic);
} else {
// Update existing filter
savedData = await FilterModel.update(filterID, filter, title, isPublic);
}
delete({ accountID, userID, filterID })
Deletes user's filter.
Validation:
- User must own the filter
- Default filters cannot be deleted
🔀 Integration Points
- CRM Contacts - Queries contacts collection via count providers
- CRM Deals - Queries deals collection via count providers
- Pipelines - Respects deal pipeline permissions
⚠️ Important Notes
- 🔒 Ownership: Only filter creator can edit/delete (unless admin)
- 🔢 Real-time Counts: Counts calculated on every filter list request (performance impact)
- 📊 Default Filters: System filters are immutable - updates create copies
- 👥 Team Visibility: Public filters visible to all account members
Last Updated: 2025-10-08
Module Path:internal/api/v1/filters/