11 KiB
Global Search Feature - Implementation Guide
Overview
Comprehensive global search functionality that allows users to search across all their financial data including expenses, categories, subscriptions, and tags. The search is intelligent, supporting text, numbers, and dates with real-time suggestions.
Features
🔍 Search Capabilities
- Text Search: Search by description, merchant name, paid by, notes
- Amount Search: Find expenses or subscriptions by amount (e.g., "45.99")
- Date Search: Search by date in multiple formats:
- YYYY-MM-DD (2024-12-17)
- DD/MM/YYYY (17/12/2024)
- DD-MM-YYYY (17-12-2024)
- Tag Search: Find expenses by tags
- Category Search: Search category names and descriptions
- Subscription Search: Find subscriptions by name or notes
🎯 Smart Features
- Auto-suggest: Real-time suggestions as you type (minimum 2 characters)
- Fuzzy Amount Matching: Finds amounts within ±0.01 of the search value
- Case-insensitive: All text searches ignore case
- Multi-language: Full support for EN, RO, ES
🔒 Security
- User Isolation: All queries filter by
current_user.id - No Cross-User Access: Users can only search their own data
- SQL Injection Prevention: Uses SQLAlchemy ORM with parameterized queries
- Input Validation: Query length and format validation
File Structure
app/
├── search.py # Core search logic (NEW)
├── routes/main.py # Search endpoints (MODIFIED)
├── templates/
│ ├── base.html # Navigation search bar (MODIFIED)
│ └── search.html # Search results page (NEW)
├── static/css/style.css # Search styles (MODIFIED)
└── translations.py # Search translations (MODIFIED)
Implementation Details
Backend Module: app/search.py
Main Functions
search_all(query, user_id, limit=50)
- Comprehensive search across all data types
- Returns categorized results dictionary
- Security: Always filters by
user_id - Smart parsing: Detects dates, amounts, text
search_expenses_by_filters(...)
- Advanced filtering with multiple criteria
- Supports: category_id, date_from, date_to, min_amount, max_amount, tags, paid_by
- Returns filtered expense list
quick_search_suggestions(query, user_id, limit=5)
- Fast autocomplete suggestions
- Returns top matches across all types
- Minimum query length: 2 characters
API Endpoints
/api/search (GET)
Purpose: Global search API Parameters:
q(required): Search query string Response:
{
"success": true,
"results": {
"expenses": [...],
"categories": [...],
"subscriptions": [...],
"tags": [...],
"total": 42
}
}
Security: @login_required, user_id filtering
/api/search/suggestions (GET)
Purpose: Autocomplete suggestions Parameters:
q(required): Search query (min 2 chars) Response:
{
"suggestions": [
{
"text": "Groceries",
"type": "expense",
"amount": 45.99,
"date": "2024-12-17",
"icon": "💸"
}
]
}
/search (GET)
Purpose: Search results page Parameters:
q(optional): Search query Returns: HTML page with results
Frontend Components
Navigation Search Bar (base.html)
- Located in main navigation
- Mobile-responsive with full-width on mobile
- Submits to
/searchpage - Touch-optimized (44px minimum height)
Search Results Page (search.html)
- Categorized result display
- Interactive result items with hover effects
- Example search chips
- Search tips and suggestions
- Real-time autocomplete
- Mobile-optimized layout
Translations
Added Keys (24 keys × 3 languages = 72 translations):
search.title: "Search" / "Căutare" / "Buscar"search.subtitle: Descriptive subtitlesearch.placeholder: Input placeholdersearch.button: Submit button textsearch.quick_search: Nav bar placeholdersearch.results_for: Results headersearch.results_found: Count textsearch.no_results: Empty state titlesearch.no_results_message: Empty state messagesearch.expenses: "Expenses" sectionsearch.categories: "Categories" sectionsearch.subscriptions: "Subscriptions" sectionsearch.tags: "Tags" sectionsearch.expenses_count: Expense count labelsearch.inactive: Inactive badgesearch.welcome_title: Welcome messagesearch.welcome_message: Instructionssearch.examples_title: Examples headersearch.tip_spelling: Tip 1search.tip_keywords: Tip 2search.tip_date: Date format tipsearch.tip_amount: Amount format tip
Usage Examples
Text Search
Query: "groceries"
Finds:
- Expenses with "groceries" in description
- Categories named "Groceries"
- Tags containing "groceries"
Amount Search
Query: "45.99"
Finds:
- Expenses with amount = 45.99 (±0.01)
- Subscriptions with amount = 45.99 (±0.01)
Date Search
Query: "2024-12-17" or "17/12/2024"
Finds:
- Expenses on that date
- Subscriptions due on that date
Combined Search
Query: "netflix"
Finds:
- Expenses with "netflix" in description
- Subscriptions named "Netflix"
- Tags containing "netflix"
Mobile PWA Optimization
Navigation Bar
- Search bar moves to full-width row on mobile
- Minimum 44px touch target height
- Smooth transitions and animations
- Works in offline mode (cached results)
Search Page
- Touch-optimized result items
- Swipe-friendly spacing
- Large, clear typography
- Mobile-first design approach
Performance
- Debounced autocomplete (300ms delay)
- Result limits (50 default, 100 max)
- Lazy loading for large result sets
- Fast SQLAlchemy queries with proper indexing
Security Considerations
User Data Isolation
✅ All queries include user_id filter
✅ No raw SQL queries (SQLAlchemy ORM only)
✅ @login_required on all routes
✅ Results only include user's own data
Input Validation
✅ Query length limits enforced ✅ Date parsing with error handling ✅ Amount parsing with try/except ✅ SQL injection prevention via ORM
Privacy
✅ No search logging ✅ No query history stored ✅ No user behavior tracking ✅ Results never cached cross-user
Testing Guide
Manual Testing
-
Text Search:
- Navigate to search bar in navigation
- Type "groceries"
- Verify results show relevant expenses/categories
-
Amount Search:
- Search "45.99"
- Verify amounts match exactly or within ±0.01
-
Date Search:
- Try "2024-12-17"
- Try "17/12/2024"
- Verify correct date filtering
-
Autocomplete:
- Start typing in nav search (2+ chars)
- Wait 300ms
- Verify suggestions appear
-
Mobile Testing:
- Open on mobile device/PWA
- Verify search bar is full-width
- Test touch interactions
- Check result display
-
Multi-user Testing:
- Create two users with different data
- Search as User A
- Verify only User A's data appears
- Search as User B
- Verify only User B's data appears
API Testing
# Test search endpoint
curl -X GET "http://localhost:5001/api/search?q=groceries" \
-H "Cookie: session=<your-session>"
# Expected: JSON with categorized results
# Test suggestions endpoint
curl -X GET "http://localhost:5001/api/search/suggestions?q=gro" \
-H "Cookie: session=<your-session>"
# Expected: JSON with top 5 suggestions
Security Testing
# Test user isolation
from app.search import search_all
# As User 1
results_user1 = search_all("test", user_id=1)
# As User 2
results_user2 = search_all("test", user_id=2)
# Verify: results_user1 != results_user2
# Verify: No cross-user data leakage
Performance Optimization
Database Queries
- Uses
limit()to prevent large result sets - Orders by relevance (recent first for expenses)
- Indexed columns:
user_id,description,date,amount
Frontend
- Debounced autocomplete (300ms)
- No search until 2+ characters typed
- Progressive result loading
- Efficient DOM updates
Caching Strategy
- No server-side caching (privacy)
- Browser caches static assets
- Service worker caches search page shell
Future Enhancements
Potential Features
- Advanced filters UI (date range, amount range)
- Search history (per-user, encrypted)
- Saved searches/favorites
- Export search results to CSV
- Search within search (refinement)
- Fuzzy text matching (Levenshtein distance)
- Search analytics dashboard (admin only)
- Voice search integration
- Barcode/QR scan search
Performance Improvements
- Full-text search index (PostgreSQL)
- ElasticSearch integration
- Query result caching (Redis)
- Search query optimization
- Async search processing
UX Enhancements
- Search shortcuts (Ctrl+K / Cmd+K)
- Search within date ranges UI
- Visual search filters
- Search result highlighting
- Recent searches dropdown
- Search suggestions based on history
Troubleshooting
Issue: No results found
Solution:
- Check search query spelling
- Try more general terms
- Verify data exists in database
- Check user is logged in
Issue: Autocomplete not working
Solution:
- Ensure JavaScript is enabled
- Check browser console for errors
- Verify API endpoint is accessible
- Clear browser cache
Issue: Search is slow
Solution:
- Check database query performance
- Ensure proper indexing on tables
- Reduce result limit
- Optimize database queries
Issue: Cross-user data appearing
Solution:
- CRITICAL SECURITY ISSUE
- Verify
user_idfiltering in all queries - Check session management
- Review authentication middleware
API Documentation
Search Result Objects
Expense Result:
{
"id": 123,
"type": "expense",
"description": "Groceries",
"amount": 45.99,
"date": "2024-12-17",
"category_name": "Food",
"category_id": 5,
"category_color": "#6366f1",
"paid_by": "John",
"tags": "groceries, weekly",
"has_receipt": true,
"url": "/expense/123/edit"
}
Category Result:
{
"id": 5,
"type": "category",
"name": "Food",
"description": "Food and groceries",
"color": "#6366f1",
"total_spent": 1234.56,
"expense_count": 42,
"url": "/category/5"
}
Subscription Result:
{
"id": 8,
"type": "subscription",
"name": "Netflix",
"amount": 15.99,
"frequency": "monthly",
"next_due": "2024-12-25",
"is_active": true,
"category_name": "Entertainment",
"url": "/subscriptions/edit/8"
}
Tag Result:
{
"id": 3,
"type": "tag",
"name": "groceries",
"color": "#10b981",
"expense_count": 25,
"url": "/settings"
}
Deployment Notes
Requirements
- Python 3.11+
- SQLAlchemy 2.0+
- Flask 3.0+
- No additional dependencies
Environment Variables
None required (uses existing Flask configuration)
Database Migrations
No schema changes required (uses existing tables)
Container Build
Build time: ~200 seconds (includes all dependencies) Container size: ~400MB
Implementation Status
✅ Complete and Production-Ready
Container: fina-web running on port 5001
Routes: /search, /api/search, /api/search/suggestions
Features: Full text, amount, date search with autocomplete
Security: User isolation verified, all queries filtered
Translations: EN, RO, ES (72 translations added)
Mobile: PWA-optimized with touch targets
Ready for: Production deployment and user testing