Major Changes:
- Implement bulk delete functionality for tasks with custom confirmation dialog
* Add /tasks/bulk-delete POST route with permission checks
* Add checkboxes and "Delete Selected" button to task list
* Skip tasks with time entries, provide detailed feedback
* Log all deletions for audit trail
Improve task workflows and overall UX, and align backend routes with the
new UI flows. Update docs and development setup accordingly.
- UI: refine task list/view/edit templates, project views, and Kanban
partial (`_kanban_tailwind.html`)
- CSS: polish `app/static/enhanced-ui.css` for spacing, layout, and
responsiveness
- Routes: update `app/routes/tasks.py` and `app/routes/clients.py` to
support new edit/delete/filter behaviors and validations
- Templates: align clients/projects pages for consistency and navigation
- Docs: refresh `docs/GETTING_STARTED.md` and
`docs/TASK_MANAGEMENT_README.md`
- Dev: adjust `docker-compose.yml` and `setup.py` to match the latest
runtime/build expectations
- Tests: add coverage for delete actions, task project editing, and task
filters UI (`tests/test_delete_actions.py`,
`tests/test_task_edit_project.py`,
`tests/test_tasks_filters_ui.py`); update existing tests
Why:
- Streamlines common task operations and improves discoverability
- Ensures backend and UI are consistent and well-tested
- Enhanced invoice creation form with auto-fill client data from project selection
- Redesigned invoice edit page with improved layout and quick actions sidebar
- Added new generate-from-time template for adding unbilled time entries and costs
- Improved form styling and added responsive design enhancements
- Added internationalization (i18n) support throughout invoice templates
- Added notes and terms fields to invoice forms
- Implemented item removal functionality in invoice editor
- Added comprehensive tests for new invoice features
- Updated .gitignore to exclude logs directory
- Bumped version from 3.0.0 to 3.2.0
The invoice UI now provides:
- Quick actions panel with export, duplicate, and payment recording links
- Invoice summary sidebar showing totals and status
- Tips and guidance sidebars for better UX
- Client data auto-population when selecting projects
- Improved visual hierarchy and mobile responsiveness
- Simplify docker-compose setup and align environment defaults
- Update README and Quick Start to reflect the new compose flow
- Refine app initialization and configuration for clearer env handling
- Minor consistency and cleanup in config modules
No breaking changes expected.
Implement comprehensive analytics and monitoring system with PostHog integration,
complete observability stack (Prometheus, Grafana, Loki, Promtail), and CI/CD
workflows for automated builds.
Features:
- Add PostHog telemetry integration with privacy-focused event tracking
- Implement installation flow for opt-in telemetry configuration
- Add telemetry management UI in admin panel with detailed transparency
- Track key user events across all major features (projects, tasks, timer, etc.)
Infrastructure:
- Set up Prometheus for metrics collection
- Configure Grafana for visualization dashboards
- Integrate Loki and Promtail for log aggregation
- Add separate analytics docker-compose configuration
CI/CD:
- Add GitHub Actions workflows for building and publishing Docker images
- Implement separate dev and production build pipelines
- Configure automated image publishing to registry
Documentation:
- Restructure documentation into organized docs/ directory
- Add comprehensive guides for telemetry, analytics, and local development
- Create transparency documentation for tracked events
- Add CI/CD and build configuration guides
Code improvements:
- Integrate telemetry hooks across all route handlers
- Add feature flags and configuration management
- Refactor test suite for analytics functionality
- Clean up root directory by moving docs and removing test artifacts
Breaking changes:
- Requires new environment variables for PostHog configuration
- Docker compose setup now supports analytics stack
Changes: 73 files changed, 955 insertions(+), 14126 deletions(-)
Fixed multiple issues with keyboard shortcuts and browser notifications:
Keyboard Shortcuts:
- Fixed Ctrl+/ not working to focus search input
- Resolved conflict between three event handlers (base.html, commands.js, keyboard-shortcuts-advanced.js)
- Changed inline handler from Ctrl+K to Ctrl+/ to avoid command palette conflict
- Updated search bar UI badge to display Ctrl+/ instead of Ctrl+K
- Removed conflicting ? key handler from commands.js (now uses Shift+? for shortcuts panel)
- Improved key detection to properly handle special characters like / and ?
- Added debug logging for troubleshooting keyboard events
Final keyboard mapping:
- Ctrl+K: Open Command Palette
- Ctrl+/: Focus Search Input
- Shift+?: Show All Keyboard Shortcuts
- Esc: Close Modals/Panels
Notification System:
- Fixed "right-hand side of 'in' should be an object" error in smart-notifications.js
- Changed notification permission request to follow browser security policies
- Permission now checked silently on load, only requested on user interaction
- Added "Enable Notifications" banner in notification center panel
- Fixed service worker sync check to properly verify registration object
Browser Compatibility:
- All fixes respect browser security policies for notification permissions
- Graceful degradation when service worker features unavailable
- Works correctly on Chrome, Firefox, Safari, and Edge
Files modified:
- app/static/enhanced-search.js
- app/static/keyboard-shortcuts-advanced.js
- app/static/smart-notifications.js
- app/templates/base.html
- app/static/commands.js
Closes issues with keyboard shortcuts not responding and browser console errors.
ixes #88
When OIDC_POST_LOGOUT_REDIRECT_URI was unset, the application was still
attempting RP-Initiated Logout by falling back to a generated redirect URL.
This caused issues with OIDC providers like Authelia that don't support
RP-Initiated Logout, resulting in failed redirects to unsupported endpoints.
Changes:
- Modified logout logic in app/routes/auth.py to only attempt provider
logout when OIDC_POST_LOGOUT_REDIRECT_URI is explicitly configured
- If unset, users are now logged out locally and redirected to the
TimeTracker login page (expected behavior)
- If set, RP-Initiated Logout proceeds as before (backward compatible)
Documentation:
- Updated docs/OIDC_SETUP.md with guidance on when to set the config
- Added clear comments in env.example explaining optional behavior
- Documented troubleshooting steps for providers without RP-Initiated
Logout support (e.g., Authelia)
Tests:
- Added comprehensive test suite (tests/test_oidc_logout.py) with 9 tests
covering different logout scenarios and edge cases
- All existing tests continue to pass (no regressions)
This change is fully backward compatible. Users with providers supporting
RP-Initiated Logout can continue using OIDC_POST_LOGOUT_REDIRECT_URI as
before. Users with providers like Authelia should leave it unset for
local-only logout.
Add WTF_CSRF_TRUSTED_ORIGINS to app/config.py (env-driven, comma-separated; default https://track.example.com) to allow CSRF validation when referrer/origin host matches a trusted origin behind a proxy.
Keep existing ProxyFix(x_proto=1, x_host=1, x_for=1, x_port=1) so Flask honors X-Forwarded-* headers.
Ensure forms/AJAX post to the same origin you’ve configured via WTF_CSRF_TRUSTED_ORIGINS.
The OIDC callback was failing because parse_id_token() was called without
the required 'nonce' parameter, causing authentication to fail with a
TypeError. This prevented the issuer (iss) claim from being extracted,
which is required for successful OIDC login.
Changes:
- Check if ID token claims are already available in the token response
under 'userinfo' key (parsed by Authlib during authorize_access_token)
- If not available, retrieve nonce from session and pass it to
parse_id_token() method
- This ensures the issuer and subject claims are properly extracted from
the ID token instead of only relying on the userinfo endpoint
The issuer claim is only present in the ID token, not the userinfo
endpoint, so proper ID token parsing is essential for authentication.
Fixes #<issue_number>
Add comprehensive HTTPS support with two deployment options:
- mkcert for local development with trusted certificates
- Automatic SSL with Let's Encrypt for production
HTTPS Implementation:
- Add docker-compose.https-mkcert.yml for local HTTPS development
- Add docker-compose.https-auto.yml for automatic SSL certificates
- Create Dockerfile.mkcert for certificate generation
- Add setup scripts (setup-https-mkcert.sh/bat)
- Add startup scripts (start-https.sh/bat)
- Add certificate generation script (generate-mkcert-certs.sh)
CSRF and IP Access Fixes:
- Fix CSRF token validation for IP-based access
- Add CSRF troubleshooting documentation
- Update configuration to handle various access patterns
Documentation:
- Add HTTPS_MKCERT_GUIDE.md with setup instructions
- Add README_HTTPS.md with general HTTPS documentation
- Add README_HTTPS_AUTO.md for automatic SSL setup
- Add AUTOMATIC_HTTPS_SUMMARY.md
- Add CSRF_IP_ACCESS_FIX.md and CSRF_IP_FIX_SUMMARY.md
- Add docs/CSRF_IP_ACCESS_GUIDE.md
- Update main README.md with HTTPS information
Configuration:
- Update .gitignore for SSL certificates and nginx configs
- Update env.example with new HTTPS-related variables
- Update docker-compose.yml with SSL configuration options
This enables secure HTTPS access in both development and production
environments while maintaining compatibility with existing deployments.
Implement comprehensive CSRF token management with cookie-based
double-submit pattern to improve security and SPA compatibility.
Changes:
- Add CSRF cookie configuration in app/config.py
* WTF_CSRF_SSL_STRICT for strict SSL validation in production
* CSRF_COOKIE_NAME (default: XSRF-TOKEN) for framework compatibility
* CSRF_COOKIE_SECURE inherits from SESSION_COOKIE_SECURE by default
* CSRF_COOKIE_HTTPONLY, CSRF_COOKIE_SAMESITE, and CSRF_COOKIE_DOMAIN settings
- Implement CSRF cookie handler in app/__init__.py
* Set CSRF token in cookie after each request
* Configure cookie with secure flags based on environment settings
* Support for double-submit pattern and SPA frameworks
- Add client-side CSRF token management in base.html
* JavaScript utilities for token retrieval and validation
* Cookie synchronization for frameworks that read XSRF-TOKEN
* Auto-refresh mechanism for stale tokens (>15 minutes)
* Pre-submit token validation and refresh
* User notification for missing cookies/tokens
- Clean up docker-compose.yml environment variables
* Remove redundant SECRET_KEY, WTF_CSRF_*, and cookie security settings
* These are now managed through .env files and config.py
This enhancement provides better CSRF protection while maintaining
compatibility with modern JavaScript frameworks and SPA architectures.
- Fix infinite recursion error in showToast function by removing duplicate local definition
- Implement dynamic calendar legend that updates with actual project names and colors
- Add comprehensive button state management to prevent stuck "Processing..." states
- Implement immediate loading state clearing for all calendar actions (create, update, delete, duplicate)
- Add resetAllButtonStates() function to handle button state cleanup
- Remove delays in loading state transitions for better responsiveness
- Add error handling and logging for calendar events loading
- Ensure loading states are cleared on both success and error scenarios
- Add global reset function for manual button state recovery
- Improve loadTasksForProject error handling and null checks
Fixes:
- Calendar legend showing static placeholders instead of dynamic project data
- Buttons stuck in "Processing..." state after successful actions
- Loading states persisting for 2-3 seconds after completion
- Recursion errors in toast notification system
- Inconsistent button state management across calendar operations
- CSRF error handler:
- Treat classic form POSTs as HTML (flash + safe redirect) regardless of
Accept header quirks; return JSON only for XHR/JSON requests
- Add contextual logging (path, method, referrer, user, reason) for diagnostics
- Security/config:
- Enforce strong SECRET_KEY in production (no placeholders, min length);
refuse startup if invalid
- Make SESSION_COOKIE_SAMESITE and REMEMBER_COOKIE_SAMESITE env-driven
while keeping Secure/HttpOnly flags configurable
- Client resilience:
- Refresh CSRF token on window focus in addition to periodic refresh
- Pre-submit refresh if token is stale (>15 minutes)
- Auto-inject/refresh tokens for dynamically added forms via MutationObserver
- UX correctness:
- Ensure tasks.edit_task re-renders with projects/users on validation errors
Fixes#77 (csrf_token_missing_or_invalid)
See: https://github.com/DRYTRIX/TimeTracker/issues/77
Files:
- app/__init__.py
- app/config.py
- app/templates/base.html
- app/routes/tasks.py
Note: In production, a single, persistent SECRET_KEY is required across all instances.