- Webhook models: remove duplicate index definitions so db.create_all()
no longer raises 'index already exists' (columns already have index=True)
- ImportService: fix circular import by late-importing ClientService,
ProjectService, TimeTrackingService in __init__
- reports: fix F823 by renaming unpack variable _ to _entry_count to avoid
shadowing gettext _ in export_task_excel()
- Code quality: add .flake8 with extend-ignore so flake8 CI passes;
simplify pyproject.toml isort config (drop unsupported options)
- Format: run black and isort on app/
- tests: restore minimal app fixture in test_import_export_models
- Lead to Client: stop passing status into Client(); set after create (#514)
- Leads/Deals activity: parse datetime-local single string in timezone util (#513)
- Deal page: add audit tracking for Deal, entity history support, History section (#515)
Refs #513, #514, #515
Co-authored-by: Cursor <cursoragent@cursor.com>
- Audit: remove session.flush() from after_flush handler to avoid
'Session is already flushing' when logging creates
- Audit smoke tests: make assertions robust to fixture-created logs
(filter by user_id/action, expect >= counts where appropriate)
- PDF preview: add id and client to mock invoice SimpleNamespace and
use getattr(invoice, 'id', None) in exception logging
- PDF layout tests: assert custom_css is contained in saved CSS
(app normalizes with @page); create template before preview test
- Session: add password to login data in smoke tests that use the
login endpoint (admin_users, permissions_routes, tasks_templates,
time_entry_resume, invoices) so sessions persist across requests
Add comprehensive audit logging for TimeEntry operations including:
- Client/project context and creation timestamps
- Full entity state before/after changes
- User-provided reasons for deletions and modifications
- Enhanced UI for entering reasons in delete/edit dialogs
Database Changes:
- Add migration 114: reason, entity_metadata, full_old_state, full_new_state columns
- Use JSON column type for entity_metadata for better type handling
Model Updates:
- Extend AuditLog model with new fields and helper methods
- Update log_change() to accept reason, metadata, and full states
- Add get_entity_metadata(), get_full_old_state(), get_full_new_state() methods
- Use JSON column for entity_metadata (returns dict/list directly)
Service Layer:
- Update TimeTrackingService to capture full TimeEntry state and metadata
- Accept reason parameter in delete_entry() and update_entry()
- Create comprehensive audit logs with all context
API Routes:
- Update api.py, api_v1.py, and timer.py routes to accept reason parameter
- Refactor routes to use service layer for consistent audit logging
- Add reason support to bulk delete operations
UI Enhancements:
- Add reason textarea to bulk delete confirmation dialog
- Add reason textarea to time entry edit forms (admin and regular users)
- Update JavaScript to handle reason submission
Audit Log Display:
- Show client/project information and creation timestamp in list view
- Display full old/new states, reason, and metadata in detail view
- Format JSON states for better readability
Bug Fixes:
- Fix duration_seconds reference in timer stop route
- Improve error handling in timer operations with proper exception handling
- Add dashboard cache invalidation after manual entry creation
Audit logs were not recording any changes because after_flush runs
after SQL is emitted; by then session.new, session.dirty, and
session.deleted can be cleared and attribute history for updates is
often consumed, so the handler saw nothing to log.
Changes:
- Add receive_before_flush: process session.dirty (updates) and
session.deleted (deletes) while history is still valid; stash
session.new (creates) in session.info for after_flush.
- Simplify receive_after_flush: only handle pending creates from
session.info (instances now have ids), then session.flush() so
audit rows are in the same transaction.
- Register receive_before_flush for before_flush on Session,
sessionmaker class, and SignallingSession.
- Make receive_before_flush accept (session, flush_context, instances)
to match SQLAlchemy's before_flush signature.
- Remove db.session.flush() from AuditLog.log_change to avoid
nested flush; rely on main flush or explicit flush in after_flush.
- check_audit_logging.py: use entity_type='TimeEntry' to match
get_entity_type (model __class__.__name__).
- test_audit_logging: assert at least one AuditLog for create/update/
delete; use test_client for create; fix update to merge then mutate.
- Improve audit logging error messages to distinguish table missing errors from other failures
- Add warning-level logging for audit_logs table missing scenarios with migration guidance
- Update audit event listener with better error detection and logging
- Add comprehensive diagnostic script for checking audit logging setup
- Update UI templates (base.html, admin forms, user settings, profile pages)
- Extend audit logging support across routes (admin, api, permissions, reports, timer, user)
- Add extensive test coverage for admin user management functionality
- Update time tracking service and user model with audit logging integration
- Normalize line endings from CRLF to LF across all files to match .editorconfig
- Standardize quote style from single quotes to double quotes
- Normalize whitespace and formatting throughout codebase
- Apply consistent code style across 372 files including:
* Application code (models, routes, services, utils)
* Test files
* Configuration files
* CI/CD workflows
This ensures consistency with the project's .editorconfig settings and
improves code maintainability.
Implement a complete audit logging system to track all changes made to
tracked entities, providing full compliance and accountability capabilities.
Features:
- Automatic tracking of create, update, and delete operations on 25+ models
- Detailed field-level change tracking with old/new value comparison
- User attribution with IP address, user agent, and request path logging
- Web UI for viewing and filtering audit logs with pagination
- REST API endpoints for programmatic access
- Entity-specific history views
- Comprehensive test coverage (unit, model, route, and smoke tests)
Core Components:
- AuditLog model with JSON-encoded value storage and decoding helpers
- SQLAlchemy event listeners for automatic change detection
- Audit utility module with defensive programming for table existence checks
- Blueprint routes for audit log viewing and API access
- Jinja2 templates for audit log list, detail, and entity history views
- Database migration (044) creating audit_logs table with proper indexes
Technical Implementation:
- Uses SQLAlchemy 'after_flush' event listener to capture changes
- Tracks 25+ models including Projects, Tasks, TimeEntries, Invoices, Clients, Users, etc.
- Excludes sensitive fields (passwords) and system fields (id, timestamps)
- Implements lazy import pattern to avoid circular dependencies
- Graceful error handling to prevent audit logging from breaking core functionality
- Transaction-safe logging that integrates with main application transactions
Fixes:
- Resolved login errors caused by premature transaction commits
- Fixed circular import issues with lazy model loading
- Added table existence checks to prevent errors before migrations
- Improved error handling with debug-level logging for non-critical failures
UI/UX:
- Added "Audit Logs" link to admin dropdown menu
- Organized admin menu into logical sections for better usability
- Filterable audit log views by entity type, user, action, and date range
- Color-coded action badges and side-by-side old/new value display
- Pagination support for large audit log datasets
Documentation:
- Added comprehensive feature documentation
- Included troubleshooting guide and data examples
- Created diagnostic scripts for verifying audit log setup
Testing:
- Unit tests for AuditLog model and value encoding/decoding
- Route tests for all audit log endpoints
- Integration tests for audit logging functionality
- Smoke tests for end-to-end audit trail verification
This implementation provides a robust foundation for compliance tracking
and change accountability without impacting application performance or
requiring code changes in existing routes/models.